diff --git a/docker-compose-dev.yaml b/docker-compose-dev.yaml index 521897da..786c03ab 100644 --- a/docker-compose-dev.yaml +++ b/docker-compose-dev.yaml @@ -4,8 +4,9 @@ version: '3.8' x-airflow-common: &airflow-common - image: apache/airflow:2.7.2-python3.9 - # build: . + build: + context: . + dockerfile: Dockerfile-airflow-domino.dev environment: &airflow-common-env AIRFLOW__CORE__EXECUTOR: CeleryExecutor @@ -226,10 +227,6 @@ services: # Modified Airflow Scheduler with Domino airflow-scheduler: <<: *airflow-common - # # image: ghcr.io/tauffer-consulting/domino-airflow-base:latest - build: - context: . - dockerfile: Dockerfile-airflow-domino.dev container_name: airflow-domino-scheduler command: scheduler healthcheck: @@ -261,10 +258,6 @@ services: # Modified Airflow Worker with Domino airflow-worker: <<: *airflow-common - # image: ghcr.io/tauffer-consulting/domino-airflow-base:latest - build: - context: . - dockerfile: Dockerfile-airflow-domino.dev container_name: airflow-domino-worker command: celery worker healthcheck: diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index 409c6007..9bc42126 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -7,7 +7,8 @@ "extends": [ "standard-with-typescript", "plugin:react/recommended", - "plugin:prettier/recommended" + "plugin:prettier/recommended", + "plugin:@tanstack/eslint-plugin-query/recommended" ], "parserOptions": { "ecmaVersion": "latest", diff --git a/frontend/Dockerfile.dev b/frontend/Dockerfile.dev index 38117907..11123da1 100644 --- a/frontend/Dockerfile.dev +++ b/frontend/Dockerfile.dev @@ -20,6 +20,4 @@ FROM base WORKDIR /usr/src/app COPY --from=build /usr/src/app/node_modules ./node_modules COPY . . -RUN chmod -R 777 node_modules/ -USER node CMD ["pnpm", "run", "debug"] diff --git a/frontend/package.json b/frontend/package.json index d92f0493..5af4a84d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,74 +5,70 @@ "engines": { "node": ">=18 < 20" }, + "browserslist": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "scripts": { + "debug": "VITE_CJS_IGNORE_WARNING=true vite dev", + "start": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext js,jsx,ts,tsx", + "lint:fix": "eslint . --ext js,jsx,ts,tsx --fix" + }, "dependencies": { - "@emotion/react": "^11.11.3", + "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@iconify/react": "^4.1.1", "@import-meta-env/cli": "^0.6.8", "@import-meta-env/unplugin": "^0.4.10", - "@mui/icons-material": "^5.15.10", + "@mui/icons-material": "^5.15.14", "@mui/lab": "5.0.0-alpha.165", - "@mui/material": "^5.15.10", - "@mui/x-data-grid": "^6.19.4", - "@mui/x-date-pickers": "^6.19.4", + "@mui/material": "^5.15.14", + "@mui/x-data-grid": "^6.19.6", + "@mui/x-date-pickers": "^6.19.7", + "@tanstack/react-query": "^5.28.4", + "@tanstack/react-query-devtools": "^5.28.4", "@uiw/react-textarea-code-editor": "^2.1.9", "@vitejs/plugin-react": "^4.2.1", - "axios": "^1.6.7", + "axios": "^1.6.8", "axios-mock-adapter": "^1.22.0", "cross-env": "^7.0.3", "dayjs": "^1.11.10", "elkjs": "^0.8.2", "pdfjs-dist": "^3.11.174", - "plotly.js": "^2.29.1", + "plotly.js": "^2.30.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-draggable": "^4.4.6", - "react-hook-form": "^7.50.1", + "react-hook-form": "^7.51.1", "react-markdown": "9.0.0", - "react-pdf": "^7.7.0", + "react-pdf": "^7.7.1", "react-plotly.js": "^2.6.0", - "react-router-dom": "^6.22.0", - "react-to-print": "^2.14.15", + "react-router-dom": "^6.22.3", + "react-to-print": "^2.15.1", "react-toastify": "^9.1.3", - "reactflow": "^11.10.3", + "reactflow": "^11.10.4", "remark-gfm": "^4.0.0", - "swr": "^2.2.4", + "swr": "^2.2.5", "uuid": "^9.0.1", - "vite": "^5.1.1", + "vite": "^5.1.6", "vite-plugin-svgr": "^4.2.0", - "vite-tsconfig-paths": "^4.3.1", + "vite-tsconfig-paths": "^4.3.2", "web-worker": "^1.3.0", - "yup": "^1.3.3" - }, - "scripts": { - "debug": "VITE_CJS_IGNORE_WARNING=true vite dev", - "start": "vite", - "start:mock": "cross-env NODE_OPTIONS=--openssl-legacy-provider VITE_USE_MOCK=true vite", - "build": "tsc && vite build", - "lint": "eslint . --ext js,jsx,ts,tsx", - "lint:fix": "eslint . --ext js,jsx,ts,tsx --fix" + "yup": "^1.4.0" }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": [ - ">0.2%", - "not dead", - "not op_mini all" - ], "devDependencies": { + "@tanstack/eslint-plugin-query": "^5.27.7", "@types/dompurify": "^3.0.5", - "@types/react": "^18.2.55", - "@types/react-dom": "^18.2.19", + "@types/react": "^18.2.67", + "@types/react-dom": "^18.2.22", "@types/react-plotly.js": "^2.6.3", "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", - "eslint": "^8.56.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-config-standard-with-typescript": "^39.1.1", "eslint-import-resolver-typescript": "^3.6.1", @@ -80,10 +76,16 @@ "eslint-plugin-n": "^16.6.2", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-testing-library": "^6.2.0", "prettier": "^3.2.5", - "typescript": "^5.3.3" + "typescript": "^5.4.2" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 1d746a67..eb24e106 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -6,47 +6,53 @@ settings: dependencies: '@emotion/react': - specifier: ^11.11.3 - version: 11.11.3(@types/react@18.2.55)(react@18.2.0) + specifier: ^11.11.4 + version: 11.11.4(@types/react@18.2.67)(react@18.2.0) '@emotion/styled': specifier: ^11.11.0 - version: 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.55)(react@18.2.0) + version: 11.11.0(@emotion/react@11.11.4)(@types/react@18.2.67)(react@18.2.0) '@iconify/react': specifier: ^4.1.1 version: 4.1.1(react@18.2.0) '@import-meta-env/cli': specifier: ^0.6.8 - version: 0.6.8(@import-meta-env/unplugin@0.4.10)(dotenv@16.4.4) + version: 0.6.8(@import-meta-env/unplugin@0.4.10)(dotenv@16.4.5) '@import-meta-env/unplugin': specifier: ^0.4.10 - version: 0.4.10(@import-meta-env/cli@0.6.8)(dotenv@16.4.4) + version: 0.4.10(@import-meta-env/cli@0.6.8)(dotenv@16.4.5) '@mui/icons-material': - specifier: ^5.15.10 - version: 5.15.10(@mui/material@5.15.10)(@types/react@18.2.55)(react@18.2.0) + specifier: ^5.15.14 + version: 5.15.14(@mui/material@5.15.14)(@types/react@18.2.67)(react@18.2.0) '@mui/lab': specifier: 5.0.0-alpha.165 - version: 5.0.0-alpha.165(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@mui/material@5.15.10)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + version: 5.0.0-alpha.165(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@mui/material@5.15.14)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) '@mui/material': - specifier: ^5.15.10 - version: 5.15.10(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + specifier: ^5.15.14 + version: 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) '@mui/x-data-grid': - specifier: ^6.19.4 - version: 6.19.4(@mui/material@5.15.10)(@mui/system@5.15.9)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + specifier: ^6.19.6 + version: 6.19.6(@mui/material@5.15.14)(@mui/system@5.15.14)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) '@mui/x-date-pickers': - specifier: ^6.19.4 - version: 6.19.4(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@mui/material@5.15.10)(@mui/system@5.15.9)(@types/react@18.2.55)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0) + specifier: ^6.19.7 + version: 6.19.7(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@mui/material@5.15.14)(@mui/system@5.15.14)(@types/react@18.2.67)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-query': + specifier: ^5.28.4 + version: 5.28.4(react@18.2.0) + '@tanstack/react-query-devtools': + specifier: ^5.28.4 + version: 5.28.4(@tanstack/react-query@5.28.4)(react@18.2.0) '@uiw/react-textarea-code-editor': specifier: ^2.1.9 - version: 2.1.9(@babel/runtime@7.23.9)(react-dom@18.2.0)(react@18.2.0) + version: 2.1.9(@babel/runtime@7.24.1)(react-dom@18.2.0)(react@18.2.0) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.1) + version: 4.2.1(vite@5.1.6) axios: - specifier: ^1.6.7 - version: 1.6.7 + specifier: ^1.6.8 + version: 1.6.8 axios-mock-adapter: specifier: ^1.22.0 - version: 1.22.0(axios@1.6.7) + version: 1.22.0(axios@1.6.8) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -60,8 +66,8 @@ dependencies: specifier: ^3.11.174 version: 3.11.174 plotly.js: - specifier: ^2.29.1 - version: 2.29.1(mapbox-gl@1.13.3) + specifier: ^2.30.1 + version: 2.30.1(mapbox-gl@1.13.3) react: specifier: ^18.2.0 version: 18.2.0 @@ -72,64 +78,67 @@ dependencies: specifier: ^4.4.6 version: 4.4.6(react-dom@18.2.0)(react@18.2.0) react-hook-form: - specifier: ^7.50.1 - version: 7.50.1(react@18.2.0) + specifier: ^7.51.1 + version: 7.51.1(react@18.2.0) react-markdown: specifier: 9.0.0 - version: 9.0.0(@types/react@18.2.55)(react@18.2.0) + version: 9.0.0(@types/react@18.2.67)(react@18.2.0) react-pdf: - specifier: ^7.7.0 - version: 7.7.0(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + specifier: ^7.7.1 + version: 7.7.1(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) react-plotly.js: specifier: ^2.6.0 - version: 2.6.0(plotly.js@2.29.1)(react@18.2.0) + version: 2.6.0(plotly.js@2.30.1)(react@18.2.0) react-router-dom: - specifier: ^6.22.0 - version: 6.22.0(react-dom@18.2.0)(react@18.2.0) + specifier: ^6.22.3 + version: 6.22.3(react-dom@18.2.0)(react@18.2.0) react-to-print: - specifier: ^2.14.15 - version: 2.14.15(react-dom@18.2.0)(react@18.2.0) + specifier: ^2.15.1 + version: 2.15.1(react-dom@18.2.0)(react@18.2.0) react-toastify: specifier: ^9.1.3 version: 9.1.3(react-dom@18.2.0)(react@18.2.0) reactflow: - specifier: ^11.10.3 - version: 11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + specifier: ^11.10.4 + version: 11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) remark-gfm: specifier: ^4.0.0 version: 4.0.0 swr: - specifier: ^2.2.4 - version: 2.2.4(react@18.2.0) + specifier: ^2.2.5 + version: 2.2.5(react@18.2.0) uuid: specifier: ^9.0.1 version: 9.0.1 vite: - specifier: ^5.1.1 - version: 5.1.1 + specifier: ^5.1.6 + version: 5.1.6 vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(typescript@5.3.3)(vite@5.1.1) + version: 4.2.0(typescript@5.4.2)(vite@5.1.6) vite-tsconfig-paths: - specifier: ^4.3.1 - version: 4.3.1(typescript@5.3.3)(vite@5.1.1) + specifier: ^4.3.2 + version: 4.3.2(typescript@5.4.2)(vite@5.1.6) web-worker: specifier: ^1.3.0 version: 1.3.0 yup: - specifier: ^1.3.3 - version: 1.3.3 + specifier: ^1.4.0 + version: 1.4.0 devDependencies: + '@tanstack/eslint-plugin-query': + specifier: ^5.27.7 + version: 5.27.7(eslint@8.57.0)(typescript@5.4.2) '@types/dompurify': specifier: ^3.0.5 version: 3.0.5 '@types/react': - specifier: ^18.2.55 - version: 18.2.55 + specifier: ^18.2.67 + version: 18.2.67 '@types/react-dom': - specifier: ^18.2.19 - version: 18.2.19 + specifier: ^18.2.22 + version: 18.2.22 '@types/react-plotly.js': specifier: ^2.6.3 version: 2.6.3 @@ -138,49 +147,49 @@ devDependencies: version: 9.0.8 '@typescript-eslint/eslint-plugin': specifier: ^6.21.0 - version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3) + version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.2) '@typescript-eslint/parser': specifier: ^6.21.0 - version: 6.21.0(eslint@8.56.0)(typescript@5.3.3) + version: 6.21.0(eslint@8.57.0)(typescript@5.4.2) eslint: - specifier: ^8.56.0 - version: 8.56.0 + specifier: ^8.57.0 + version: 8.57.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@8.56.0) + version: 9.1.0(eslint@8.57.0) eslint-config-standard-with-typescript: specifier: ^39.1.1 - version: 39.1.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3) + version: 39.1.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.57.0)(typescript@5.4.2) eslint-import-resolver-typescript: specifier: ^3.6.1 - version: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + version: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + version: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-n: specifier: ^16.6.2 - version: 16.6.2(eslint@8.56.0) + version: 16.6.2(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.5) + version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) eslint-plugin-promise: specifier: ^6.1.1 - version: 6.1.1(eslint@8.56.0) + version: 6.1.1(eslint@8.57.0) eslint-plugin-react: - specifier: ^7.33.2 - version: 7.33.2(eslint@8.56.0) + specifier: ^7.34.1 + version: 7.34.1(eslint@8.57.0) eslint-plugin-react-hooks: specifier: ^4.6.0 - version: 4.6.0(eslint@8.56.0) + version: 4.6.0(eslint@8.57.0) eslint-plugin-testing-library: specifier: ^6.2.0 - version: 6.2.0(eslint@8.56.0)(typescript@5.3.3) + version: 6.2.0(eslint@8.57.0)(typescript@5.4.2) prettier: specifier: ^3.2.5 version: 3.2.5 typescript: - specifier: ^5.3.3 - version: 5.3.3 + specifier: ^5.4.2 + version: 5.4.2 packages: @@ -189,41 +198,41 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 dev: false - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + /@babel/code-frame@7.24.2: + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 + '@babel/highlight': 7.24.2 + picocolors: 1.0.0 dev: false - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} + /@babel/compat-data@7.24.1: + resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} engines: {node: '>=6.9.0'} dev: false - /@babel/core@7.23.9: - resolution: {integrity: sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==} + /@babel/core@7.24.1: + resolution: {integrity: sha512-F82udohVyIgGAY2VVj/g34TpFUG606rumIHjTfVbssPg2zTR7PuuEpZcX8JA6sgBfIYmJrFtWgPvHQuJamVqZQ==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.1 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.9) - '@babel/helpers': 7.23.9 - '@babel/parser': 7.23.9 - '@babel/template': 7.23.9 - '@babel/traverse': 7.23.9 - '@babel/types': 7.23.9 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.1) + '@babel/helpers': 7.24.1 + '@babel/parser': 7.24.1 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 convert-source-map: 2.0.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -233,13 +242,13 @@ packages: - supports-color dev: false - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + /@babel/generator@7.24.1: + resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 + '@babel/types': 7.24.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 dev: false @@ -247,9 +256,9 @@ packages: resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.23.5 + '@babel/compat-data': 7.24.1 '@babel/helper-validator-option': 7.23.5 - browserslist: 4.22.3 + browserslist: 4.23.0 lru-cache: 5.1.1 semver: 6.3.1 dev: false @@ -263,40 +272,40 @@ packages: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.23.9 - '@babel/types': 7.23.9 + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 dev: false /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + /@babel/helper-module-imports@7.24.1: + resolution: {integrity: sha512-HfEWzysMyOa7xI5uQHc/OcZf67/jc+xe/RZlznWQHhbb8Pg1SkRdbK4yEi61aY8wxQA7PkSfoojtLQP/Kpe3og==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.9): + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.1): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 + '@babel/helper-module-imports': 7.24.1 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 dev: false - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + /@babel/helper-plugin-utils@7.24.0: + resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} engines: {node: '>=6.9.0'} dev: false @@ -304,18 +313,18 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + /@babel/helper-string-parser@7.24.1: + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} engines: {node: '>=6.9.0'} dev: false @@ -329,93 +338,94 @@ packages: engines: {node: '>=6.9.0'} dev: false - /@babel/helpers@7.23.9: - resolution: {integrity: sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==} + /@babel/helpers@7.24.1: + resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.23.9 - '@babel/traverse': 7.23.9 - '@babel/types': 7.23.9 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 transitivePeerDependencies: - supports-color dev: false - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + /@babel/highlight@7.24.2: + resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 + picocolors: 1.0.0 dev: false - /@babel/parser@7.23.9: - resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} + /@babel/parser@7.24.1: + resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false - /@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.23.9): - resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==} + /@babel/plugin-transform-react-jsx-self@7.24.1(@babel/core@7.24.1): + resolution: {integrity: sha512-kDJgnPujTmAZ/9q2CN4m2/lRsUUPDvsG3+tSHWUJIzMGTt5U/b/fwWd3RO3n+5mjLrsBrVa5eKFRVSQbi3dF1w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.1 + '@babel/helper-plugin-utils': 7.24.0 dev: false - /@babel/plugin-transform-react-jsx-source@7.23.3(@babel/core@7.23.9): - resolution: {integrity: sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==} + /@babel/plugin-transform-react-jsx-source@7.24.1(@babel/core@7.24.1): + resolution: {integrity: sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.1 + '@babel/helper-plugin-utils': 7.24.0 dev: false - /@babel/runtime@7.23.9: - resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} + /@babel/runtime@7.24.1: + resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 dev: false - /@babel/template@7.23.9: - resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} + /@babel/template@7.24.0: + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/code-frame': 7.24.2 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 dev: false - /@babel/traverse@7.23.9: - resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} + /@babel/traverse@7.24.1: + resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.1 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: false - /@babel/types@7.23.9: - resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} + /@babel/types@7.24.0: + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.23.4 + '@babel/helper-string-parser': 7.24.1 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 dev: false @@ -430,8 +440,8 @@ packages: /@emotion/babel-plugin@11.11.0: resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: - '@babel/helper-module-imports': 7.22.15 - '@babel/runtime': 7.23.9 + '@babel/helper-module-imports': 7.24.1 + '@babel/runtime': 7.24.1 '@emotion/hash': 0.9.1 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.3 @@ -457,8 +467,8 @@ packages: resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} dev: false - /@emotion/is-prop-valid@1.2.1: - resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==} + /@emotion/is-prop-valid@1.2.2: + resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==} dependencies: '@emotion/memoize': 0.8.1 dev: false @@ -467,8 +477,8 @@ packages: resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} dev: false - /@emotion/react@11.11.3(@types/react@18.2.55)(react@18.2.0): - resolution: {integrity: sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==} + /@emotion/react@11.11.4(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==} peerDependencies: '@types/react': '*' react: '>=16.8.0' @@ -476,14 +486,14 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 '@emotion/babel-plugin': 11.11.0 '@emotion/cache': 11.11.0 '@emotion/serialize': 1.1.3 '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) '@emotion/utils': 1.2.1 '@emotion/weak-memoize': 0.3.1 - '@types/react': 18.2.55 + '@types/react': 18.2.67 hoist-non-react-statics: 3.3.2 react: 18.2.0 dev: false @@ -502,7 +512,7 @@ packages: resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} dev: false - /@emotion/styled@11.11.0(@emotion/react@11.11.3)(@types/react@18.2.55)(react@18.2.0): + /@emotion/styled@11.11.0(@emotion/react@11.11.4)(@types/react@18.2.67)(react@18.2.0): resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==} peerDependencies: '@emotion/react': ^11.0.0-rc.0 @@ -512,14 +522,14 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 '@emotion/babel-plugin': 11.11.0 - '@emotion/is-prop-valid': 1.2.1 - '@emotion/react': 11.11.3(@types/react@18.2.55)(react@18.2.0) + '@emotion/is-prop-valid': 1.2.2 + '@emotion/react': 11.11.4(@types/react@18.2.67)(react@18.2.0) '@emotion/serialize': 1.1.3 '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) '@emotion/utils': 1.2.1 - '@types/react': 18.2.55 + '@types/react': 18.2.67 react: 18.2.0 dev: false @@ -750,13 +760,13 @@ packages: dev: false optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.56.0 + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 dev: true @@ -782,8 +792,8 @@ packages: - supports-color dev: true - /@eslint/js@8.56.0: - resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==} + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -848,7 +858,7 @@ packages: resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} dev: false - /@import-meta-env/cli@0.6.8(@import-meta-env/unplugin@0.4.10)(dotenv@16.4.4): + /@import-meta-env/cli@0.6.8(@import-meta-env/unplugin@0.4.10)(dotenv@16.4.5): resolution: {integrity: sha512-Lunsmlj02yVtI5drlhNwIUFAQ0wsIUYIrz0Nm5jbvmYvyEUsxC8Qotnf3gXTfvM9Yuutvuc2+dx4uXpa3DajTg==} engines: {node: '>= 14'} hasBin: true @@ -865,15 +875,15 @@ packages: '@import-meta-env/unplugin': optional: true dependencies: - '@import-meta-env/unplugin': 0.4.10(@import-meta-env/cli@0.6.8)(dotenv@16.4.4) + '@import-meta-env/unplugin': 0.4.10(@import-meta-env/cli@0.6.8)(dotenv@16.4.5) commander: 11.1.0 - dotenv: 16.4.4 + dotenv: 16.4.5 glob: 10.3.10 picocolors: 1.0.0 serialize-javascript: 6.0.1 dev: false - /@import-meta-env/unplugin@0.4.10(@import-meta-env/cli@0.6.8)(dotenv@16.4.4): + /@import-meta-env/unplugin@0.4.10(@import-meta-env/cli@0.6.8)(dotenv@16.4.5): resolution: {integrity: sha512-KA/JjnhHp2vrPA27J+IFj/XVDMJz7+jUmyukDAmMoF2uW5q8F3pJySrfl/vySLV1SVxa2b4zg2kuAe5CTIs+Bg==} engines: {node: '>= 14'} requiresBuild: true @@ -884,12 +894,12 @@ packages: '@import-meta-env/cli': optional: true dependencies: - '@import-meta-env/cli': 0.6.8(@import-meta-env/unplugin@0.4.10)(dotenv@16.4.4) - dotenv: 16.4.4 - magic-string: 0.30.7 + '@import-meta-env/cli': 0.6.8(@import-meta-env/unplugin@0.4.10)(dotenv@16.4.5) + dotenv: 16.4.5 + magic-string: 0.30.8 object-hash: 3.0.0 picocolors: 1.0.0 - unplugin: 1.7.1 + unplugin: 1.10.0 dev: false /@isaacs/cliui@8.0.2: @@ -904,22 +914,22 @@ packages: wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: false - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/set-array': 1.1.2 + '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 dev: false - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} dev: false - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} dev: false @@ -927,10 +937,10 @@ packages: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: false - /@jridgewell/trace-mapping@0.3.22: - resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: - '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 dev: false @@ -964,7 +974,7 @@ packages: hasBin: true requiresBuild: true dependencies: - detect-libc: 2.0.2 + detect-libc: 2.0.3 https-proxy-agent: 5.0.1 make-dir: 3.1.0 node-fetch: 2.7.0 @@ -1002,7 +1012,7 @@ packages: engines: {node: '>=6.0.0'} dev: false - /@mui/base@5.0.0-beta.36(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): + /@mui/base@5.0.0-beta.36(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-6A8fYiXgjqTO6pgj31Hc8wm1M3rFYCxDRh09dBVk0L0W4cb2lnurRJa3cAyic6hHY+we1S58OdGYRbKmOsDpGQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -1013,24 +1023,47 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 + '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0) + '@mui/types': 7.2.14(@types/react@18.2.67) + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) + '@popperjs/core': 2.11.8 + '@types/react': 18.2.67 + clsx: 2.1.0 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@mui/base@5.0.0-beta.40(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.1 '@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0) - '@mui/types': 7.2.13(@types/react@18.2.55) - '@mui/utils': 5.15.9(@types/react@18.2.55)(react@18.2.0) + '@mui/types': 7.2.14(@types/react@18.2.67) + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) '@popperjs/core': 2.11.8 - '@types/react': 18.2.55 + '@types/react': 18.2.67 clsx: 2.1.0 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@mui/core-downloads-tracker@5.15.10: - resolution: {integrity: sha512-qPv7B+LeMatYuzRjB3hlZUHqinHx/fX4YFBiaS19oC02A1e9JFuDKDvlyRQQ5oRSbJJt0QlaLTlr0IcauVcJRQ==} + /@mui/core-downloads-tracker@5.15.14: + resolution: {integrity: sha512-on75VMd0XqZfaQW+9pGjSNiqW+ghc5E2ZSLRBXwcXl/C4YzjfyjrLPhrEpKnR9Uym9KXBvxrhoHfPcczYHweyA==} dev: false - /@mui/icons-material@5.15.10(@mui/material@5.15.10)(@types/react@18.2.55)(react@18.2.0): - resolution: {integrity: sha512-9cF8oUHZKo9oQ7EQ3pxPELaZuZVmphskU4OI6NiJNDVN7zcuvrEsuWjYo1Zh4fLiC39Nrvm30h/B51rcUjvSGA==} + /@mui/icons-material@5.15.14(@mui/material@5.15.14)(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-vj/51k7MdFmt+XVw94sl30SCvGx6+wJLsNYjZRgxhS6y3UtnWnypMOsm3Kmg8TN+P0dqwsjy4/fX7B1HufJIhw==} engines: {node: '>=12.0.0'} peerDependencies: '@mui/material': ^5.0.0 @@ -1040,13 +1073,13 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 - '@mui/material': 5.15.10(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.55 + '@babel/runtime': 7.24.1 + '@mui/material': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.67 react: 18.2.0 dev: false - /@mui/lab@5.0.0-alpha.165(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@mui/material@5.15.10)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): + /@mui/lab@5.0.0-alpha.165(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@mui/material@5.15.14)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-8/zJStT10nh9yrAzLOPTICGhpf5YiGp/JpM0bdTP7u5AE+YT+X2u6QwMxuCrVeW8/WVLAPFg0vtzyfgPcN5T7g==} engines: {node: '>=12.0.0'} peerDependencies: @@ -1064,23 +1097,23 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 - '@emotion/react': 11.11.3(@types/react@18.2.55)(react@18.2.0) - '@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.55)(react@18.2.0) - '@mui/base': 5.0.0-beta.36(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@mui/material': 5.15.10(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@mui/system': 5.15.9(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react@18.2.0) - '@mui/types': 7.2.13(@types/react@18.2.55) - '@mui/utils': 5.15.9(@types/react@18.2.55)(react@18.2.0) - '@types/react': 18.2.55 + '@babel/runtime': 7.24.1 + '@emotion/react': 11.11.4(@types/react@18.2.67)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.4)(@types/react@18.2.67)(react@18.2.0) + '@mui/base': 5.0.0-beta.36(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@mui/material': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@mui/system': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react@18.2.0) + '@mui/types': 7.2.14(@types/react@18.2.67) + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 clsx: 2.1.0 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@mui/material@5.15.10(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-YJJGHjwDOucecjDEV5l9ISTCo+l9YeWrho623UajzoHRYxuKUmwrGVYOW4PKwGvCx9SU9oklZnbbi2Clc5XZHw==} + /@mui/material@5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-kEbRw6fASdQ1SQ7LVdWR5OlWV3y7Y54ZxkLzd6LV5tmz+NpO3MJKZXSfgR0LHMP7meKsPiMm4AuzV0pXDpk/BQ==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -1096,15 +1129,15 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 - '@emotion/react': 11.11.3(@types/react@18.2.55)(react@18.2.0) - '@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.55)(react@18.2.0) - '@mui/base': 5.0.0-beta.36(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@mui/core-downloads-tracker': 5.15.10 - '@mui/system': 5.15.9(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react@18.2.0) - '@mui/types': 7.2.13(@types/react@18.2.55) - '@mui/utils': 5.15.9(@types/react@18.2.55)(react@18.2.0) - '@types/react': 18.2.55 + '@babel/runtime': 7.24.1 + '@emotion/react': 11.11.4(@types/react@18.2.67)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.4)(@types/react@18.2.67)(react@18.2.0) + '@mui/base': 5.0.0-beta.40(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@mui/core-downloads-tracker': 5.15.14 + '@mui/system': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react@18.2.0) + '@mui/types': 7.2.14(@types/react@18.2.67) + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 '@types/react-transition-group': 4.4.10 clsx: 2.1.0 csstype: 3.1.3 @@ -1115,8 +1148,8 @@ packages: react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) dev: false - /@mui/private-theming@5.15.9(@types/react@18.2.55)(react@18.2.0): - resolution: {integrity: sha512-/aMJlDOxOTAXyp4F2rIukW1O0anodAMCkv1DfBh/z9vaKHY3bd5fFf42wmP+0GRmwMinC5aWPpNfHXOED1fEtg==} + /@mui/private-theming@5.15.14(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 @@ -1125,15 +1158,15 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 - '@mui/utils': 5.15.9(@types/react@18.2.55)(react@18.2.0) - '@types/react': 18.2.55 + '@babel/runtime': 7.24.1 + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 prop-types: 15.8.1 react: 18.2.0 dev: false - /@mui/styled-engine@5.15.9(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0): - resolution: {integrity: sha512-NRKtYkL5PZDH7dEmaLEIiipd3mxNnQSO+Yo8rFNBNptY8wzQnQ+VjayTq39qH7Sast5cwHKYFusUrQyD+SS4Og==} + /@mui/styled-engine@5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(react@18.2.0): + resolution: {integrity: sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.4.1 @@ -1145,17 +1178,17 @@ packages: '@emotion/styled': optional: true dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 '@emotion/cache': 11.11.0 - '@emotion/react': 11.11.3(@types/react@18.2.55)(react@18.2.0) - '@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.55)(react@18.2.0) + '@emotion/react': 11.11.4(@types/react@18.2.67)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.4)(@types/react@18.2.67)(react@18.2.0) csstype: 3.1.3 prop-types: 15.8.1 react: 18.2.0 dev: false - /@mui/system@5.15.9(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react@18.2.0): - resolution: {integrity: sha512-SxkaaZ8jsnIJ77bBXttfG//LUf6nTfOcaOuIgItqfHv60ZCQy/Hu7moaob35kBb+guxVJnoSZ+7vQJrA/E7pKg==} + /@mui/system@5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-auXLXzUaCSSOLqJXmsAaq7P96VPRXg2Rrz6OHNV7lr+kB8lobUF+/N84Vd9C4G/wvCXYPs5TYuuGBRhcGbiBGg==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -1170,33 +1203,33 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 - '@emotion/react': 11.11.3(@types/react@18.2.55)(react@18.2.0) - '@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.55)(react@18.2.0) - '@mui/private-theming': 5.15.9(@types/react@18.2.55)(react@18.2.0) - '@mui/styled-engine': 5.15.9(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) - '@mui/types': 7.2.13(@types/react@18.2.55) - '@mui/utils': 5.15.9(@types/react@18.2.55)(react@18.2.0) - '@types/react': 18.2.55 + '@babel/runtime': 7.24.1 + '@emotion/react': 11.11.4(@types/react@18.2.67)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.4)(@types/react@18.2.67)(react@18.2.0) + '@mui/private-theming': 5.15.14(@types/react@18.2.67)(react@18.2.0) + '@mui/styled-engine': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(react@18.2.0) + '@mui/types': 7.2.14(@types/react@18.2.67) + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) + '@types/react': 18.2.67 clsx: 2.1.0 csstype: 3.1.3 prop-types: 15.8.1 react: 18.2.0 dev: false - /@mui/types@7.2.13(@types/react@18.2.55): - resolution: {integrity: sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==} + /@mui/types@7.2.14(@types/react@18.2.67): + resolution: {integrity: sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@types/react': optional: true dependencies: - '@types/react': 18.2.55 + '@types/react': 18.2.67 dev: false - /@mui/utils@5.15.9(@types/react@18.2.55)(react@18.2.0): - resolution: {integrity: sha512-yDYfr61bCYUz1QtwvpqYy/3687Z8/nS4zv7lv/ih/6ZFGMl1iolEvxRmR84v2lOYxlds+kq1IVYbXxDKh8Z9sg==} + /@mui/utils@5.15.14(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 @@ -1205,16 +1238,16 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 '@types/prop-types': 15.7.11 - '@types/react': 18.2.55 + '@types/react': 18.2.67 prop-types: 15.8.1 react: 18.2.0 react-is: 18.2.0 dev: false - /@mui/x-data-grid@6.19.4(@mui/material@5.15.10)(@mui/system@5.15.9)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-qXBe2mSetdsl3ZPqB/1LpKNkEiaYUiFXIaMHTIjuzLyusXgt+w7UsHYO7R+aJYUU7c3FeHla0R1nwRMY3kZ5ng==} + /@mui/x-data-grid@6.19.6(@mui/material@5.15.14)(@mui/system@5.15.14)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-jpZkX1Gnlo87gKcD10mKMY8YoAzUD8Cv3/IvedH3FINDKO3hnraMeOciKDeUk0tYSj8RUDB02kpTHCM8ojLVBA==} engines: {node: '>=14.0.0'} peerDependencies: '@mui/material': ^5.4.1 @@ -1222,10 +1255,10 @@ packages: react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.9 - '@mui/material': 5.15.10(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@mui/system': 5.15.9(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react@18.2.0) - '@mui/utils': 5.15.9(@types/react@18.2.55)(react@18.2.0) + '@babel/runtime': 7.24.1 + '@mui/material': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@mui/system': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react@18.2.0) + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) clsx: 2.1.0 prop-types: 15.8.1 react: 18.2.0 @@ -1235,8 +1268,8 @@ packages: - '@types/react' dev: false - /@mui/x-date-pickers@6.19.4(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@mui/material@5.15.10)(@mui/system@5.15.9)(@types/react@18.2.55)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-LekaacLGnoQNN5hD6iXeHFL4LbZPnr1BM57hnUKy5UgKDHqzHzZSdPGc2p7Ktv/Z2NDbpPaLEAgrLwISKIYcow==} + /@mui/x-date-pickers@6.19.7(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@mui/material@5.15.14)(@mui/system@5.15.14)(@types/react@18.2.67)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-BCTOQjAuyU29Ymd2FJrHHdRh0U6Qve7MsthdrD2jjaMaR8ou455JuxsNTQUGSpiMkGHWOMVq+B8N1EBcSYH63g==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.9.0 @@ -1272,13 +1305,13 @@ packages: moment-jalaali: optional: true dependencies: - '@babel/runtime': 7.23.9 - '@emotion/react': 11.11.3(@types/react@18.2.55)(react@18.2.0) - '@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.55)(react@18.2.0) - '@mui/base': 5.0.0-beta.36(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@mui/material': 5.15.10(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@mui/system': 5.15.9(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.55)(react@18.2.0) - '@mui/utils': 5.15.9(@types/react@18.2.55)(react@18.2.0) + '@babel/runtime': 7.24.1 + '@emotion/react': 11.11.4(@types/react@18.2.67)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.4)(@types/react@18.2.67)(react@18.2.0) + '@mui/base': 5.0.0-beta.40(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@mui/material': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@mui/system': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.0)(@types/react@18.2.67)(react@18.2.0) + '@mui/utils': 5.15.14(@types/react@18.2.67)(react@18.2.0) '@types/react-transition-group': 4.4.10 clsx: 2.1.0 dayjs: 1.11.10 @@ -1397,40 +1430,40 @@ packages: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false - /@reactflow/background@11.3.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-U4aI54F7PwqgYI0Knv72QFRI/wXeipPmIYAlDsA0j51+tlPxs3Nk2z7G1/4pC11GxEZkgQVfcIXro4l1Fk+bIQ==} + /@reactflow/background@11.3.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-byj/G9pEC8tN0wT/ptcl/LkEP/BBfa33/SvBkqE4XwyofckqF87lKp573qGlisfnsijwAbpDlf81PuFL41So4Q==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.5.0(@types/react@18.2.55)(react@18.2.0) + zustand: 4.5.2(@types/react@18.2.67)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/controls@11.2.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Y9YVx38sRjYtbPsI/xa+B1FGN73FV1GqqajlmGfrc1TmqhJaX+gaMXMvVazT/N5haK1hMJvOApUTLQ2V/5Rdbg==} + /@reactflow/controls@11.2.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-e8nWplbYfOn83KN1BrxTXS17+enLyFnjZPbyDgHSRLtI5ZGPKF/8iRXV+VXb2LFVzlu4Wh3la/pkxtfP/0aguA==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.5.0(@types/react@18.2.55)(react@18.2.0) + zustand: 4.5.2(@types/react@18.2.67)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/core@11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-nV3nep4fjBy3h8mYSnJcclGcQtj8fkUBmNkEwCZCK4ps+n3HNkXFB0BRisSnQz6GRQlYboSsi0cThEl3KdNITw==} + /@reactflow/core@11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-j3i9b2fsTX/sBbOm+RmNzYEFWbNx4jGWGuGooh2r1jQaE2eV+TLJgiG/VNOp0q5mBl9f6g1IXs3Gm86S9JfcGw==} peerDependencies: react: '>=17' react-dom: '>=17' @@ -1445,19 +1478,19 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.5.0(@types/react@18.2.55)(react@18.2.0) + zustand: 4.5.2(@types/react@18.2.67)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/minimap@11.7.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-MwyP5q3VomC91Dhd4P6YcxEfnjDbREGYV6rRxbSJSTHiG0x7ETQCcPelYDGy7JvQej77Pa2yJ4g0FDwP7CsQEA==} + /@reactflow/minimap@11.7.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-le95jyTtt3TEtJ1qa7tZ5hyM4S7gaEQkW43cixcMOZLu33VAdc2aCpJg/fXcRrrf7moN2Mbl9WIMNXUKsp5ILA==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) '@types/d3-selection': 3.0.10 '@types/d3-zoom': 3.0.8 classcat: 5.0.4 @@ -1465,48 +1498,48 @@ packages: d3-zoom: 3.0.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.5.0(@types/react@18.2.55)(react@18.2.0) + zustand: 4.5.2(@types/react@18.2.67)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/node-resizer@2.2.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-u/EXLpvOfAmq1sGoPYwoX4gi0PnCi0mH3eHVClHNc8JQD0WCqcV1UeVV7H3PF+1SGhhg/aOv/vPG1PcQ5fu4jQ==} + /@reactflow/node-resizer@2.2.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HfickMm0hPDIHt9qH997nLdgLt0kayQyslKE0RS/GZvZ4UMQJlx/NRRyj5y47Qyg0NnC66KYOQWDM9LLzRTnUg==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 d3-drag: 3.0.0 d3-selection: 3.0.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.5.0(@types/react@18.2.55)(react@18.2.0) + zustand: 4.5.2(@types/react@18.2.67)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/node-toolbar@1.3.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-cfvlTPeJa/ciQTosx2bGrjHT8K/UL9kznpvpOzeZFnJm5UQXmbwAYt4Vo6GfkD51mORcIL7ujQJvB9ym3ZI9KA==} + /@reactflow/node-toolbar@1.3.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-VmgxKmToax4sX1biZ9LXA7cj/TBJ+E5cklLGwquCCVVxh+lxpZGTBF3a5FJGVHiUNBBtFsC8ldcSZIK4cAlQww==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) classcat: 5.0.4 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - zustand: 4.5.0(@types/react@18.2.55)(react@18.2.0) + zustand: 4.5.2(@types/react@18.2.67)(react@18.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@remix-run/router@1.15.0: - resolution: {integrity: sha512-HOil5aFtme37dVQTB6M34G95kPM3MMuqSmIRVCC52eKV+Y/tGSqw9P3rWhlAx6A+mz+MoX+XxsGsNJbaI5qCgQ==} + /@remix-run/router@1.15.3: + resolution: {integrity: sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==} engines: {node: '>=14.0.0'} dev: false @@ -1524,207 +1557,207 @@ packages: picomatch: 2.3.1 dev: false - /@rollup/rollup-android-arm-eabi@4.10.0: - resolution: {integrity: sha512-/MeDQmcD96nVoRumKUljsYOLqfv1YFJps+0pTrb2Z9Nl/w5qNUysMaWQsrd1mvAlNT4yza1iVyIu4Q4AgF6V3A==} + /@rollup/rollup-android-arm-eabi@4.13.0: + resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==} cpu: [arm] os: [android] requiresBuild: true dev: false optional: true - /@rollup/rollup-android-arm64@4.10.0: - resolution: {integrity: sha512-lvu0jK97mZDJdpZKDnZI93I0Om8lSDaiPx3OiCk0RXn3E8CMPJNS/wxjAvSJJzhhZpfjXsjLWL8LnS6qET4VNQ==} + /@rollup/rollup-android-arm64@4.13.0: + resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==} cpu: [arm64] os: [android] requiresBuild: true dev: false optional: true - /@rollup/rollup-darwin-arm64@4.10.0: - resolution: {integrity: sha512-uFpayx8I8tyOvDkD7X6n0PriDRWxcqEjqgtlxnUA/G9oS93ur9aZ8c8BEpzFmsed1TH5WZNG5IONB8IiW90TQg==} + /@rollup/rollup-darwin-arm64@4.13.0: + resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==} cpu: [arm64] os: [darwin] requiresBuild: true dev: false optional: true - /@rollup/rollup-darwin-x64@4.10.0: - resolution: {integrity: sha512-nIdCX03qFKoR/MwQegQBK+qZoSpO3LESurVAC6s6jazLA1Mpmgzo3Nj3H1vydXp/JM29bkCiuF7tDuToj4+U9Q==} + /@rollup/rollup-darwin-x64@4.13.0: + resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==} cpu: [x64] os: [darwin] requiresBuild: true dev: false optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.10.0: - resolution: {integrity: sha512-Fz7a+y5sYhYZMQFRkOyCs4PLhICAnxRX/GnWYReaAoruUzuRtcf+Qnw+T0CoAWbHCuz2gBUwmWnUgQ67fb3FYw==} + /@rollup/rollup-linux-arm-gnueabihf@4.13.0: + resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==} cpu: [arm] os: [linux] requiresBuild: true dev: false optional: true - /@rollup/rollup-linux-arm64-gnu@4.10.0: - resolution: {integrity: sha512-yPtF9jIix88orwfTi0lJiqINnlWo6p93MtZEoaehZnmCzEmLL0eqjA3eGVeyQhMtxdV+Mlsgfwhh0+M/k1/V7Q==} + /@rollup/rollup-linux-arm64-gnu@4.13.0: + resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==} cpu: [arm64] os: [linux] requiresBuild: true dev: false optional: true - /@rollup/rollup-linux-arm64-musl@4.10.0: - resolution: {integrity: sha512-9GW9yA30ib+vfFiwjX+N7PnjTnCMiUffhWj4vkG4ukYv1kJ4T9gHNg8zw+ChsOccM27G9yXrEtMScf1LaCuoWQ==} + /@rollup/rollup-linux-arm64-musl@4.13.0: + resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==} cpu: [arm64] os: [linux] requiresBuild: true dev: false optional: true - /@rollup/rollup-linux-riscv64-gnu@4.10.0: - resolution: {integrity: sha512-X1ES+V4bMq2ws5fF4zHornxebNxMXye0ZZjUrzOrf7UMx1d6wMQtfcchZ8SqUnQPPHdOyOLW6fTcUiFgHFadRA==} + /@rollup/rollup-linux-riscv64-gnu@4.13.0: + resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==} cpu: [riscv64] os: [linux] requiresBuild: true dev: false optional: true - /@rollup/rollup-linux-x64-gnu@4.10.0: - resolution: {integrity: sha512-w/5OpT2EnI/Xvypw4FIhV34jmNqU5PZjZue2l2Y3ty1Ootm3SqhI+AmfhlUYGBTd9JnpneZCDnt3uNOiOBkMyw==} + /@rollup/rollup-linux-x64-gnu@4.13.0: + resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==} cpu: [x64] os: [linux] requiresBuild: true dev: false optional: true - /@rollup/rollup-linux-x64-musl@4.10.0: - resolution: {integrity: sha512-q/meftEe3QlwQiGYxD9rWwB21DoKQ9Q8wA40of/of6yGHhZuGfZO0c3WYkN9dNlopHlNT3mf5BPsUSxoPuVQaw==} + /@rollup/rollup-linux-x64-musl@4.13.0: + resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==} cpu: [x64] os: [linux] requiresBuild: true dev: false optional: true - /@rollup/rollup-win32-arm64-msvc@4.10.0: - resolution: {integrity: sha512-NrR6667wlUfP0BHaEIKgYM/2va+Oj+RjZSASbBMnszM9k+1AmliRjHc3lJIiOehtSSjqYiO7R6KLNrWOX+YNSQ==} + /@rollup/rollup-win32-arm64-msvc@4.13.0: + resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==} cpu: [arm64] os: [win32] requiresBuild: true dev: false optional: true - /@rollup/rollup-win32-ia32-msvc@4.10.0: - resolution: {integrity: sha512-FV0Tpt84LPYDduIDcXvEC7HKtyXxdvhdAOvOeWMWbQNulxViH2O07QXkT/FffX4FqEI02jEbCJbr+YcuKdyyMg==} + /@rollup/rollup-win32-ia32-msvc@4.13.0: + resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==} cpu: [ia32] os: [win32] requiresBuild: true dev: false optional: true - /@rollup/rollup-win32-x64-msvc@4.10.0: - resolution: {integrity: sha512-OZoJd+o5TaTSQeFFQ6WjFCiltiYVjIdsXxwu/XZ8qRpsvMQr4UsVrE5UyT9RIvsnuF47DqkJKhhVZ2Q9YW9IpQ==} + /@rollup/rollup-win32-x64-msvc@4.13.0: + resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==} cpu: [x64] os: [win32] requiresBuild: true dev: false optional: true - /@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.23.9): + /@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.24.1): resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.23.9): + /@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.24.1): resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.23.9): + /@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.24.1): resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.23.9): + /@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.24.1): resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.23.9): + /@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.24.1): resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.23.9): + /@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.24.1): resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.23.9): + /@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.24.1): resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.23.9): + /@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.24.1): resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} engines: {node: '>=12'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 + '@babel/core': 7.24.1 dev: false - /@svgr/babel-preset@8.1.0(@babel/core@7.23.9): + /@svgr/babel-preset@8.1.0(@babel/core@7.24.1): resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} engines: {node: '>=14'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.9 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.23.9) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.23.9) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.23.9) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.23.9) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.23.9) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.23.9) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.23.9) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.23.9) + '@babel/core': 7.24.1 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.24.1) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.24.1) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.24.1) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.24.1) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.24.1) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.24.1) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.24.1) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.24.1) dev: false - /@svgr/core@8.1.0(typescript@5.3.3): + /@svgr/core@8.1.0(typescript@5.4.2): resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} engines: {node: '>=14'} dependencies: - '@babel/core': 7.23.9 - '@svgr/babel-preset': 8.1.0(@babel/core@7.23.9) + '@babel/core': 7.24.1 + '@svgr/babel-preset': 8.1.0(@babel/core@7.24.1) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.3.3) + cosmiconfig: 8.3.6(typescript@5.4.2) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -1735,7 +1768,7 @@ packages: resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} engines: {node: '>=14'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 entities: 4.5.0 dev: false @@ -1745,15 +1778,55 @@ packages: peerDependencies: '@svgr/core': '*' dependencies: - '@babel/core': 7.23.9 - '@svgr/babel-preset': 8.1.0(@babel/core@7.23.9) - '@svgr/core': 8.1.0(typescript@5.3.3) + '@babel/core': 7.24.1 + '@svgr/babel-preset': 8.1.0(@babel/core@7.24.1) + '@svgr/core': 8.1.0(typescript@5.4.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color dev: false + /@tanstack/eslint-plugin-query@5.27.7(eslint@8.57.0)(typescript@5.4.2): + resolution: {integrity: sha512-I0bQGypBu7gmbjHhRPglZRnYZObiXu7JotDxqRJfjr8sP5YiCx2zm+qbQClrgUGER++Hx4EA4suL7hSiBMWgJg==} + peerDependencies: + eslint: ^8.0.0 + dependencies: + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.2) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@tanstack/query-core@5.28.4: + resolution: {integrity: sha512-uQZqOFqLWUvXNIQZ63XdKzg22NtHzgCBUfDmjDHi3BoF+nUYeBNvMi/xFPtFrMhqRzG2Ir4mYaGsWZzmiEjXpA==} + dev: false + + /@tanstack/query-devtools@5.28.3: + resolution: {integrity: sha512-Kxch05PVnxLUAyRiz2gXYQhXATHfXbQQwvz858YPjYYQyi7yk8SyS9Z5hyw90bRb0pd3rjelXyGFCsNMWvEghw==} + dev: false + + /@tanstack/react-query-devtools@5.28.4(@tanstack/react-query@5.28.4)(react@18.2.0): + resolution: {integrity: sha512-oS+3INjCIX4Nkh0IAV6LH2mgLqJjkcd/DDxp8dwdWCGloLrz6IBj+bOuuI2wD0zb8r7l45wIAYIhl4Z6XyTupQ==} + peerDependencies: + '@tanstack/react-query': ^5.28.4 + react: ^18.0.0 + dependencies: + '@tanstack/query-devtools': 5.28.3 + '@tanstack/react-query': 5.28.4(react@18.2.0) + react: 18.2.0 + dev: false + + /@tanstack/react-query@5.28.4(react@18.2.0): + resolution: {integrity: sha512-BErcoB/QQG6YwLSUKnaGxF+lSc270RH2w3kMBpG0i4YzDCsFs2pdxPX1WVknQvFk9bNgukMb158hc2Zb4SdwSA==} + peerDependencies: + react: ^18.0.0 + dependencies: + '@tanstack/query-core': 5.28.4 + react: 18.2.0 + dev: false + /@turf/area@6.5.0: resolution: {integrity: sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==} dependencies: @@ -1788,8 +1861,8 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.5 @@ -1798,20 +1871,20 @@ packages: /@types/babel__generator@7.6.8: resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/parser': 7.24.1 + '@babel/types': 7.24.0 dev: false /@types/babel__traverse@7.20.5: resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@types/d3-array@3.2.1: @@ -1887,8 +1960,8 @@ packages: '@types/geojson': 7946.0.14 dev: false - /@types/d3-hierarchy@3.1.6: - resolution: {integrity: sha512-qlmD/8aMk5xGorUvTUWHCiumvgaUXYldYjNVOWtYoTYY/L+WwIEAmJxUmTgr9LoGNG0PPAOmqMDJVDPc7DOpPw==} + /@types/d3-hierarchy@3.1.7: + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} dev: false /@types/d3-interpolate@3.0.4: @@ -1976,7 +2049,7 @@ packages: '@types/d3-force': 3.0.9 '@types/d3-format': 3.0.4 '@types/d3-geo': 3.1.0 - '@types/d3-hierarchy': 3.1.6 + '@types/d3-hierarchy': 3.1.7 '@types/d3-interpolate': 3.0.4 '@types/d3-path': 3.1.0 '@types/d3-polygon': 3.0.2 @@ -2005,8 +2078,8 @@ packages: '@types/trusted-types': 2.0.7 dev: true - /@types/estree-jsx@1.0.4: - resolution: {integrity: sha512-5idy3hvI9lAMqsyilBM+N+boaCf1MgoefbDxN6KEO5aK17TOHwFAYT9sjxzeKAiIWRUBgLxmZ9mPcnzZXtTcRQ==} + /@types/estree-jsx@1.0.5: + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} dependencies: '@types/estree': 1.0.5 dev: false @@ -2057,8 +2130,8 @@ packages: resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} dev: false - /@types/plotly.js@2.29.1: - resolution: {integrity: sha512-rQwpL3XFqSjCjG3qTlZCDvIOgc17m/0pgOpkv0O/0awdsHD+CAxaczgJTBlAsd8OhsjIcJC3UESrbBEJ92kUVg==} + /@types/plotly.js@2.29.2: + resolution: {integrity: sha512-tJqUVa6CmNHrzTANWO/ZLNmdvjZ6zHOAnM9iQUORVnnLvWmcO9DPdQCsrNumNvHD1aqGNxQJ8pla8CK/NUiZgA==} dev: true /@types/prismjs@1.26.3: @@ -2068,27 +2141,27 @@ packages: /@types/prop-types@15.7.11: resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} - /@types/react-dom@18.2.19: - resolution: {integrity: sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA==} + /@types/react-dom@18.2.22: + resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==} dependencies: - '@types/react': 18.2.55 + '@types/react': 18.2.67 dev: true /@types/react-plotly.js@2.6.3: resolution: {integrity: sha512-HBQwyGuu/dGXDsWhnQrhH+xcJSsHvjkwfSRjP+YpOsCCWryIuXF78ZCBjpfgO3sCc0Jo8sYp4NOGtqT7Cn3epQ==} dependencies: - '@types/plotly.js': 2.29.1 - '@types/react': 18.2.55 + '@types/plotly.js': 2.29.2 + '@types/react': 18.2.67 dev: true /@types/react-transition-group@4.4.10: resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==} dependencies: - '@types/react': 18.2.55 + '@types/react': 18.2.67 dev: false - /@types/react@18.2.55: - resolution: {integrity: sha512-Y2Tz5P4yz23brwm2d7jNon39qoAtMMmalOQv6+fEFt1mT+FcM3D841wDpoUvFXhaYenuROCy3FZYqdTjM7qVyA==} + /@types/react@18.2.67: + resolution: {integrity: sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==} dependencies: '@types/prop-types': 15.7.11 '@types/scheduler': 0.16.8 @@ -2097,8 +2170,8 @@ packages: /@types/scheduler@0.16.8: resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} - /@types/semver@7.5.7: - resolution: {integrity: sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==} + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true /@types/trusted-types@2.0.7: @@ -2117,7 +2190,7 @@ packages: resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} dev: true - /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2129,24 +2202,24 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.2) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4 - eslint: 8.56.0 + eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.6.0 - ts-api-utils: 1.2.1(typescript@5.3.3) - typescript: 5.3.3 + ts-api-utils: 1.3.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2158,11 +2231,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4 - eslint: 8.56.0 - typescript: 5.3.3 + eslint: 8.57.0 + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true @@ -2183,7 +2256,7 @@ packages: '@typescript-eslint/visitor-keys': 6.21.0 dev: true - /@typescript-eslint/type-utils@6.21.0(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2193,12 +2266,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.2) debug: 4.3.4 - eslint: 8.56.0 - ts-api-utils: 1.2.1(typescript@5.3.3) - typescript: 5.3.3 + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true @@ -2213,7 +2286,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@5.62.0(typescript@5.3.3): + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.2): resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2228,13 +2301,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 - tsutils: 3.21.0(typescript@5.3.3) - typescript: 5.3.3 + tsutils: 3.21.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.21.0(typescript@5.3.3): + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.2): resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2250,25 +2323,25 @@ packages: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.0 - ts-api-utils: 1.2.1(typescript@5.3.3) - typescript: 5.3.3 + ts-api-utils: 1.3.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.62.0(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 - '@types/semver': 7.5.7 + '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.3.3) - eslint: 8.56.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.2) + eslint: 8.57.0 eslint-scope: 5.1.1 semver: 7.6.0 transitivePeerDependencies: @@ -2276,19 +2349,19 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.21.0(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 - '@types/semver': 7.5.7 + '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) - eslint: 8.56.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.2) + eslint: 8.57.0 semver: 7.6.0 transitivePeerDependencies: - supports-color @@ -2311,14 +2384,14 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@uiw/react-textarea-code-editor@2.1.9(@babel/runtime@7.23.9)(react-dom@18.2.0)(react@18.2.0): + /@uiw/react-textarea-code-editor@2.1.9(@babel/runtime@7.24.1)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-fby8oencLyF1BMAMDVIe4zErb01Qf97G25vJld6mJmgFAbK5TwFW0XUvkxAuNKaLp+EccKf5pejCVHcS/jZ3eA==} peerDependencies: '@babel/runtime': '>=7.10.0' react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) rehype: 12.0.1 @@ -2328,18 +2401,18 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@vitejs/plugin-react@4.2.1(vite@5.1.1): + /@vitejs/plugin-react@4.2.1(vite@5.1.6): resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 dependencies: - '@babel/core': 7.23.9 - '@babel/plugin-transform-react-jsx-self': 7.23.3(@babel/core@7.23.9) - '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.9) + '@babel/core': 7.24.1 + '@babel/plugin-transform-react-jsx-self': 7.24.1(@babel/core@7.24.1) + '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.1) '@types/babel__core': 7.20.5 react-refresh: 0.14.0 - vite: 5.1.1 + vite: 5.1.6 transitivePeerDependencies: - supports-color dev: false @@ -2474,7 +2547,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.22.5 get-intrinsic: 1.2.4 is-string: 1.0.7 dev: true @@ -2498,25 +2571,27 @@ packages: engines: {node: '>=8'} dev: true - /array.prototype.filter@1.0.3: - resolution: {integrity: sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==} + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 - es-array-method-boxes-properly: 1.0.0 - is-string: 1.0.7 + es-abstract: 1.23.2 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 dev: true - /array.prototype.findlastindex@1.2.4: - resolution: {integrity: sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==} + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 es-errors: 1.3.0 + es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 dev: true @@ -2526,7 +2601,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.22.5 es-shim-unscopables: 1.0.2 dev: true @@ -2536,7 +2611,16 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.22.5 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.toreversed@1.1.2: + resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 es-shim-unscopables: 1.0.2 dev: true @@ -2545,7 +2629,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.22.5 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 dev: true @@ -2557,42 +2641,38 @@ packages: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 es-errors: 1.3.0 get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.2 - dev: true - - /asynciterator.prototype@1.0.0: - resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} - dependencies: - has-symbols: 1.0.3 + is-shared-array-buffer: 1.0.3 dev: true /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: false - /available-typed-arrays@1.0.6: - resolution: {integrity: sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==} + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 dev: true - /axios-mock-adapter@1.22.0(axios@1.6.7): + /axios-mock-adapter@1.22.0(axios@1.6.8): resolution: {integrity: sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==} peerDependencies: axios: '>= 0.17.0' dependencies: - axios: 1.6.7 + axios: 1.6.8 fast-deep-equal: 3.1.3 is-buffer: 2.0.5 dev: false - /axios@1.6.7: - resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} + /axios@1.6.8: + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} dependencies: - follow-redirects: 1.15.5 + follow-redirects: 1.15.6 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -2603,7 +2683,7 @@ packages: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 cosmiconfig: 7.1.0 resolve: 1.22.8 dev: false @@ -2620,8 +2700,8 @@ packages: engines: {node: '>= 0.6.0'} dev: false - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} dev: false @@ -2661,15 +2741,15 @@ packages: dependencies: fill-range: 7.0.1 - /browserslist@4.22.3: - resolution: {integrity: sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==} + /browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001587 - electron-to-chromium: 1.4.668 + caniuse-lite: 1.0.30001599 + electron-to-chromium: 1.4.711 node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.22.3) + update-browserslist-db: 1.0.13(browserslist@4.23.0) dev: false /buffer-from@1.1.2: @@ -2695,7 +2775,7 @@ packages: es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 - set-function-length: 1.2.1 + set-function-length: 1.2.2 dev: true /callsites@3.1.0: @@ -2707,8 +2787,8 @@ packages: engines: {node: '>=10'} dev: false - /caniuse-lite@1.0.30001587: - resolution: {integrity: sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==} + /caniuse-lite@1.0.30001599: + resolution: {integrity: sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==} dev: false /canvas-fit@1.5.0: @@ -2723,7 +2803,7 @@ packages: requiresBuild: true dependencies: '@mapbox/node-pre-gyp': 1.0.11 - nan: 2.18.0 + nan: 2.19.0 simple-get: 3.1.1 transitivePeerDependencies: - encoding @@ -2815,7 +2895,7 @@ packages: /color-alpha@1.0.4: resolution: {integrity: sha512-lr8/t5NPozTSqli+duAN+x+no/2WaKTeWvxhHGN+aXT6AJ8vPlzLa7UriyjWak0pSC2jHol9JgjBYnnHsGha9A==} dependencies: - color-parse: 1.3.8 + color-parse: 1.4.3 dev: false /color-convert@1.9.3: @@ -2851,19 +2931,23 @@ packages: dtype: 2.0.0 dev: false - /color-parse@1.3.8: - resolution: {integrity: sha512-1Y79qFv0n1xair3lNMTNeoFvmc3nirMVBij24zbs1f13+7fPpQClMg5b4AuKXLt3szj7BRlHMCXHplkce6XlmA==} + /color-parse@1.4.3: + resolution: {integrity: sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A==} + dependencies: + color-name: 1.1.4 + dev: false + + /color-parse@2.0.0: + resolution: {integrity: sha512-g2Z+QnWsdHLppAbrpcFWo629kLOnOPtpxYV69GCqm92gqSgyXbzlfyN3MXs0412fPBkFmiuS+rXposgBgBa6Kg==} dependencies: color-name: 1.1.4 - defined: 1.0.1 - is-plain-obj: 1.1.0 dev: false /color-rgba@2.1.1: resolution: {integrity: sha512-VaX97wsqrMwLSOR6H7rU1Doa2zyVdmShabKrPEIFywLlHoibgD3QW9Dw6fSqM4+H/LfjprDNAUUW31qEQcGzNw==} dependencies: clamp: 1.0.1 - color-parse: 1.3.8 + color-parse: 1.4.3 color-space: 1.16.0 dev: false @@ -2943,7 +3027,7 @@ packages: yaml: 1.10.2 dev: false - /cosmiconfig@8.3.6(typescript@5.3.3): + /cosmiconfig@8.3.6(typescript@5.4.2): resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} peerDependencies: @@ -2956,7 +3040,7 @@ packages: js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 - typescript: 5.3.3 + typescript: 5.4.2 dev: false /country-regex@1.1.0: @@ -3162,13 +3246,41 @@ packages: d3-transition: 3.0.1(d3-selection@3.0.0) dev: false - /d@1.0.1: - resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} + /d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} dependencies: - es5-ext: 0.10.62 - type: 1.2.0 + es5-ext: 0.10.64 + type: 2.7.2 dev: false + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + /dayjs@1.11.10: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} dev: false @@ -3266,8 +3378,8 @@ packages: resolution: {integrity: sha512-I3JIbrnKPAntNLl1I6TpSQQdQ4AutYzv/sKMFKbepawV/hlH0GmYKhUoOEMd4xqaUHT+Bm0f4127lh5qs1m1tw==} dev: false - /detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + /detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} requiresBuild: true dev: false @@ -3303,7 +3415,7 @@ packages: /dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 csstype: 3.1.3 dev: false @@ -3314,8 +3426,8 @@ packages: tslib: 2.6.2 dev: false - /dotenv@16.4.4: - resolution: {integrity: sha512-XvPXc8XAQThSjAbY6cQ/9PcBXmFoWuw1sQ3b8HqUCR6ziGXjkTi//kB9SWa2UwqlgdAIuRqAa/9hVljzPehbYg==} + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} dev: false @@ -3352,8 +3464,8 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: false - /electron-to-chromium@1.4.668: - resolution: {integrity: sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ==} + /electron-to-chromium@1.4.711: + resolution: {integrity: sha512-hRg81qzvUEibX2lDxnFlVCHACa+LtrCPIsWAxo161LDYIB3jauf57RGsMZV9mvGwE98yGH06icj3zBEoOkxd/w==} dev: false /element-size@1.1.1: @@ -3385,8 +3497,8 @@ packages: once: 1.4.0 dev: false - /enhanced-resolve@5.15.0: - resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + /enhanced-resolve@5.16.0: + resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 @@ -3404,17 +3516,17 @@ packages: is-arrayish: 0.2.1 dev: false - /es-abstract@1.22.4: - resolution: {integrity: sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==} + /es-abstract@1.22.5: + resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 - available-typed-arrays: 1.0.6 + available-typed-arrays: 1.0.7 call-bind: 1.0.7 es-define-property: 1.0.0 es-errors: 1.3.0 - es-set-tostringtag: 2.0.2 + es-set-tostringtag: 2.0.3 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 get-intrinsic: 1.2.4 @@ -3422,15 +3534,15 @@ packages: globalthis: 1.0.3 gopd: 1.0.1 has-property-descriptors: 1.0.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 + hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 is-callable: 1.2.7 - is-negative-zero: 2.0.2 + is-negative-zero: 2.0.3 is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 + is-shared-array-buffer: 1.0.3 is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 @@ -3438,21 +3550,69 @@ packages: object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.0 + safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.1 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.5 unbox-primitive: 1.0.2 - which-typed-array: 1.1.14 + which-typed-array: 1.1.15 dev: true - /es-array-method-boxes-properly@1.0.0: - resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} + /es-abstract@1.23.2: + resolution: {integrity: sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.5 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 dev: true /es-define-property@1.0.0: @@ -3467,40 +3627,46 @@ packages: engines: {node: '>= 0.4'} dev: true - /es-iterator-helpers@1.0.16: - resolution: {integrity: sha512-CREG2A9Vq7bpDRnldhFcMKuKArvkZtsH6Y0DHOHVg49qhf+LD8uEdUM3OkOAICv0EziGtDEnQtqY2/mfBILpFw==} + /es-iterator-helpers@1.0.18: + resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==} engines: {node: '>= 0.4'} dependencies: - asynciterator.prototype: 1.0.0 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 es-errors: 1.3.0 - es-set-tostringtag: 2.0.2 + es-set-tostringtag: 2.0.3 function-bind: 1.1.2 get-intrinsic: 1.2.4 globalthis: 1.0.3 has-property-descriptors: 1.0.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 internal-slot: 1.0.7 iterator.prototype: 1.1.2 - safe-array-concat: 1.1.0 + safe-array-concat: 1.1.2 + dev: true + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 dev: true - /es-set-tostringtag@2.0.2: - resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-to-primitive@1.2.1: @@ -3512,38 +3678,40 @@ packages: is-symbol: 1.0.4 dev: true - /es5-ext@0.10.62: - resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} + /es5-ext@0.10.64: + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} engines: {node: '>=0.10'} requiresBuild: true dependencies: es6-iterator: 2.0.3 - es6-symbol: 3.1.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 next-tick: 1.1.0 dev: false /es6-iterator@2.0.3: resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} dependencies: - d: 1.0.1 - es5-ext: 0.10.62 - es6-symbol: 3.1.3 + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 dev: false - /es6-symbol@3.1.3: - resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} + /es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} dependencies: - d: 1.0.1 + d: 1.0.2 ext: 1.7.0 dev: false /es6-weak-map@2.0.3: resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} dependencies: - d: 1.0.1 - es5-ext: 0.10.62 + d: 1.0.2 + es5-ext: 0.10.64 es6-iterator: 2.0.3 - es6-symbol: 3.1.3 + es6-symbol: 3.1.4 dev: false /esbuild@0.19.12: @@ -3608,26 +3776,27 @@ packages: source-map: 0.6.1 dev: false - /eslint-compat-utils@0.1.2(eslint@8.56.0): + /eslint-compat-utils@0.1.2(eslint@8.57.0): resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 8.56.0 + eslint: 8.57.0 dev: true - /eslint-config-prettier@9.1.0(eslint@8.56.0): + /eslint-config-prettier@9.1.0(eslint@8.57.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.56.0 + eslint: 8.57.0 dev: true - /eslint-config-standard-with-typescript@39.1.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.56.0)(typescript@5.3.3): + /eslint-config-standard-with-typescript@39.1.1(@typescript-eslint/eslint-plugin@6.21.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-t6B5Ep8E4I18uuoYeYxINyqcXb2UbC0SOOTxRtBSt2JUs+EzeXbfe2oaiPs71AIdnoWhXDO2fYOHz8df3kV84A==} + deprecated: Please use eslint-config-love, instead. peerDependencies: '@typescript-eslint/eslint-plugin': ^6.4.0 eslint: ^8.0.1 @@ -3636,19 +3805,19 @@ packages: eslint-plugin-promise: ^6.0.0 typescript: '*' dependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3) - '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3) - eslint: 8.56.0 - eslint-config-standard: 17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - eslint-plugin-n: 16.6.2(eslint@8.56.0) - eslint-plugin-promise: 6.1.1(eslint@8.56.0) - typescript: 5.3.3 + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2) + eslint: 8.57.0 + eslint-config-standard: 17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-n: 16.6.2(eslint@8.57.0) + eslint-plugin-promise: 6.1.1(eslint@8.57.0) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.56.0): + /eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.57.0): resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==} engines: {node: '>=12.0.0'} peerDependencies: @@ -3657,10 +3826,10 @@ packages: eslint-plugin-n: '^15.0.0 || ^16.0.0 ' eslint-plugin-promise: ^6.0.0 dependencies: - eslint: 8.56.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - eslint-plugin-n: 16.6.2(eslint@8.56.0) - eslint-plugin-promise: 6.1.1(eslint@8.56.0) + eslint: 8.57.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-n: 16.6.2(eslint@8.57.0) + eslint-plugin-promise: 6.1.1(eslint@8.57.0) dev: true /eslint-import-resolver-node@0.3.9: @@ -3673,7 +3842,7 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0): + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -3681,12 +3850,12 @@ packages: eslint-plugin-import: '*' dependencies: debug: 4.3.4 - enhanced-resolve: 5.15.0 - eslint: 8.56.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) + enhanced-resolve: 5.16.0 + eslint: 8.57.0 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 - get-tsconfig: 4.7.2 + get-tsconfig: 4.7.3 is-core-module: 2.13.1 is-glob: 4.0.3 transitivePeerDependencies: @@ -3696,8 +3865,8 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + /eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -3717,28 +3886,28 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2) debug: 3.2.7 - eslint: 8.56.0 + eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-es-x@7.5.0(eslint@8.56.0): + /eslint-plugin-es-x@7.5.0(eslint@8.57.0): resolution: {integrity: sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 - eslint: 8.56.0 - eslint-compat-utils: 0.1.2(eslint@8.56.0) + eslint: 8.57.0 + eslint-compat-utils: 0.1.2(eslint@8.57.0) dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -3748,23 +3917,23 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.2) array-includes: 3.1.7 - array.prototype.findlastindex: 1.2.4 + array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.56.0 + eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0) - hasown: 2.0.1 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.fromentries: 2.0.7 - object.groupby: 1.0.2 - object.values: 1.1.7 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 semver: 6.3.1 tsconfig-paths: 3.15.0 transitivePeerDependencies: @@ -3773,17 +3942,17 @@ packages: - supports-color dev: true - /eslint-plugin-n@16.6.2(eslint@8.56.0): + /eslint-plugin-n@16.6.2(eslint@8.57.0): resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==} engines: {node: '>=16.0.0'} peerDependencies: eslint: '>=7.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) builtins: 5.0.1 - eslint: 8.56.0 - eslint-plugin-es-x: 7.5.0(eslint@8.56.0) - get-tsconfig: 4.7.2 + eslint: 8.57.0 + eslint-plugin-es-x: 7.5.0(eslint@8.57.0) + get-tsconfig: 4.7.3 globals: 13.24.0 ignore: 5.3.1 is-builtin-module: 3.2.1 @@ -3793,7 +3962,7 @@ packages: semver: 7.6.0 dev: true - /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.5): + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5): resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -3807,64 +3976,66 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.56.0 - eslint-config-prettier: 9.1.0(eslint@8.56.0) + eslint: 8.57.0 + eslint-config-prettier: 9.1.0(eslint@8.57.0) prettier: 3.2.5 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 dev: true - /eslint-plugin-promise@6.1.1(eslint@8.56.0): + /eslint-plugin-promise@6.1.1(eslint@8.57.0): resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.56.0 + eslint: 8.57.0 dev: true - /eslint-plugin-react-hooks@4.6.0(eslint@8.56.0): + /eslint-plugin-react-hooks@4.6.0(eslint@8.57.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.56.0 + eslint: 8.57.0 dev: true - /eslint-plugin-react@7.33.2(eslint@8.56.0): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + /eslint-plugin-react@7.34.1(eslint@8.57.0): + resolution: {integrity: sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: array-includes: 3.1.7 + array.prototype.findlast: 1.2.5 array.prototype.flatmap: 1.3.2 + array.prototype.toreversed: 1.1.2 array.prototype.tosorted: 1.1.3 doctrine: 2.1.0 - es-iterator-helpers: 1.0.16 - eslint: 8.56.0 + es-iterator-helpers: 1.0.18 + eslint: 8.57.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.7 - object.fromentries: 2.0.7 + object.entries: 1.1.8 + object.fromentries: 2.0.8 object.hasown: 1.1.3 - object.values: 1.1.7 + object.values: 1.2.0 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 string.prototype.matchall: 4.0.10 dev: true - /eslint-plugin-testing-library@6.2.0(eslint@8.56.0)(typescript@5.3.3): + /eslint-plugin-testing-library@6.2.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-+LCYJU81WF2yQ+Xu4A135CgK8IszcFcyMF4sWkbiu6Oj+Nel0TrkZq/HvDw0/1WuO3dhDQsZA/OpEMGd0NfcUw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} peerDependencies: eslint: ^7.5.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.3.3) - eslint: 8.56.0 + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.2) + eslint: 8.57.0 transitivePeerDependencies: - supports-color - typescript @@ -3891,15 +4062,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.56.0: - resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.56.0 + '@eslint/js': 8.57.0 '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -3938,6 +4109,16 @@ packages: - supports-color dev: true + /esniff@2.0.1: + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} + engines: {node: '>=0.10'} + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.2 + dev: false + /espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3988,6 +4169,13 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + /event-emitter@0.3.5: + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + dev: false + /events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -4078,13 +4266,13 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.2.9 + flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 dev: true - /flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true /flatten-vertex-data@1.0.2: @@ -4093,8 +4281,8 @@ packages: dtype: 2.0.0 dev: false - /follow-redirects@1.15.5: - resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} + /follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -4174,7 +4362,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 functions-have-names: 1.2.3 dev: true @@ -4218,9 +4406,9 @@ packages: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 + hasown: 2.0.2 dev: true /get-stream@6.0.1: @@ -4237,8 +4425,8 @@ packages: get-intrinsic: 1.2.4 dev: true - /get-tsconfig@4.7.2: - resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + /get-tsconfig@4.7.3: + resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==} dependencies: resolve-pkg-maps: 1.0.0 dev: true @@ -4517,8 +4705,8 @@ packages: es-define-property: 1.0.0 dev: true - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} dev: true @@ -4540,8 +4728,8 @@ packages: dev: false optional: true - /hasown@2.0.1: - resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 @@ -4607,7 +4795,7 @@ packages: estree-util-is-identifier-name: 3.0.0 hast-util-whitespace: 3.0.0 mdast-util-mdx-expression: 2.0.0 - mdast-util-mdx-jsx: 3.1.0 + mdast-util-mdx-jsx: 3.1.2 mdast-util-mdxjs-esm: 2.0.1 property-information: 6.4.1 space-separated-tokens: 2.0.2 @@ -4731,8 +4919,8 @@ packages: engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 - hasown: 2.0.1 - side-channel: 1.0.5 + hasown: 2.0.2 + side-channel: 1.0.6 dev: true /is-alphabetical@2.0.1: @@ -4775,7 +4963,7 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} dependencies: - binary-extensions: 2.2.0 + binary-extensions: 2.3.0 dev: false /is-boolean-object@1.1.2: @@ -4810,7 +4998,14 @@ packages: /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: - hasown: 2.0.1 + hasown: 2.0.2 + + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 + dev: true /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -4871,16 +5066,17 @@ packages: engines: {node: '>=0.10.0'} dev: false - /is-map@2.0.2: - resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} dev: true /is-mobile@4.0.0: resolution: {integrity: sha512-mlcHZA84t1qLSuWkt2v0I2l61PYdyQDt4aG1mLIXF5FDMm4+haBCxCPYSr/uwqQNRk1MiTizn0ypEuRAOLRAew==} dev: false - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} dev: true @@ -4923,12 +5119,14 @@ packages: has-tostringtag: 1.0.2 dev: true - /is-set@2.0.2: - resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} dev: true - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 dev: true @@ -4959,11 +5157,12 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} dependencies: - which-typed-array: 1.1.14 + which-typed-array: 1.1.15 dev: true - /is-weakmap@2.0.1: - resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} dev: true /is-weakref@1.0.2: @@ -4972,8 +5171,9 @@ packages: call-bind: 1.0.7 dev: true - /is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 @@ -4999,8 +5199,8 @@ packages: define-properties: 1.2.1 get-intrinsic: 1.2.4 has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.5 - set-function-name: 2.0.1 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 dev: true /jackspeak@2.3.6: @@ -5063,7 +5263,7 @@ packages: array-includes: 3.1.7 array.prototype.flat: 1.3.2 object.assign: 4.1.5 - object.values: 1.1.7 + object.values: 1.2.0 dev: true /kdbush@3.0.0: @@ -5131,8 +5331,8 @@ packages: dependencies: yallist: 4.0.0 - /magic-string@0.30.7: - resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} + /magic-string@0.30.8: + resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 @@ -5298,7 +5498,7 @@ packages: /mdast-util-mdx-expression@2.0.0: resolution: {integrity: sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==} dependencies: - '@types/estree-jsx': 1.0.4 + '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdast': 4.0.3 devlop: 1.1.0 @@ -5308,10 +5508,10 @@ packages: - supports-color dev: false - /mdast-util-mdx-jsx@3.1.0: - resolution: {integrity: sha512-A8AJHlR7/wPQ3+Jre1+1rq040fX9A4Q1jG8JxmSNp/PLPHg80A6475wxTp3KzHpApFH6yWxFotHrJQA3dXP6/w==} + /mdast-util-mdx-jsx@3.1.2: + resolution: {integrity: sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==} dependencies: - '@types/estree-jsx': 1.0.4 + '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdast': 4.0.3 '@types/unist': 3.0.2 @@ -5331,7 +5531,7 @@ packages: /mdast-util-mdxjs-esm@2.0.1: resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} dependencies: - '@types/estree-jsx': 1.0.4 + '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdast': 4.0.3 devlop: 1.1.0 @@ -5381,7 +5581,7 @@ packages: '@types/mdast': 4.0.3 dev: false - /merge-refs@1.2.2(@types/react@18.2.55): + /merge-refs@1.2.2(@types/react@18.2.67): resolution: {integrity: sha512-RwcT7GsQR3KbuLw1rRuodq4Nt547BKEBkliZ0qqsrpyNne9bGTFtsFIsIpx82huWhcl3kOlOlH4H0xkPk/DqVw==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5389,7 +5589,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.55 + '@types/react': 18.2.67 dev: false /merge2@1.4.1: @@ -5767,8 +5967,8 @@ packages: resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} dev: false - /nan@2.18.0: - resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} + /nan@2.19.0: + resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} requiresBuild: true dev: false optional: true @@ -5899,48 +6099,48 @@ packages: object-keys: 1.1.1 dev: true - /object.entries@1.1.7: - resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + /object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-object-atoms: 1.0.0 dev: true - /object.fromentries@2.0.7: - resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 + es-object-atoms: 1.0.0 dev: true - /object.groupby@1.0.2: - resolution: {integrity: sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==} + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} dependencies: - array.prototype.filter: 1.0.3 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 - es-errors: 1.3.0 + es-abstract: 1.23.2 dev: true /object.hasown@1.1.3: resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} dependencies: define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.22.5 dev: true - /object.values@1.1.7: - resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-object-atoms: 1.0.0 dev: true /once@1.3.3: @@ -6007,7 +6207,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.2 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -6063,9 +6263,18 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - /path2d-polyfill@2.0.1: - resolution: {integrity: sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==} - engines: {node: '>=8'} + /path2d-polyfill@2.1.1: + resolution: {integrity: sha512-4Rka5lN+rY/p0CdD8+E+BFv51lFaFvJOrlOhyQ+zjzyQrzyh3ozmxd1vVGGDdIbUFSBtIZLSnspxTgPT0iJhvA==} + engines: {node: '>=18'} + requiresBuild: true + dependencies: + path2d: 0.1.1 + dev: false + optional: true + + /path2d@0.1.1: + resolution: {integrity: sha512-/+S03c8AGsDYKKBtRDqieTJv2GlkMb0bWjnqOgtF6MkjdUQ9a8ARAtxWf9NgKLGm2+WQr6+/tqJdU8HNGsIDoA==} + engines: {node: '>=6'} requiresBuild: true dev: false optional: true @@ -6083,7 +6292,7 @@ packages: engines: {node: '>=18'} optionalDependencies: canvas: 2.11.2 - path2d-polyfill: 2.0.1 + path2d-polyfill: 2.1.1 transitivePeerDependencies: - encoding - supports-color @@ -6105,8 +6314,8 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - /plotly.js@2.29.1(mapbox-gl@1.13.3): - resolution: {integrity: sha512-+XirhgCh42JF/iVu/RtBRbhcs328ipinajy7hd3mnZdnQv2Th6F441DSXer5S+P0nNluNs10vAFTELo4k/icjg==} + /plotly.js@2.30.1(mapbox-gl@1.13.3): + resolution: {integrity: sha512-KE3KeM4B6qtjPU7FGOxklmwYua4nWGgr48BRMWZVysZjphlSaQLzvUAieFlUCfPBPfJIRBLxFQy1KHMIQgfwrA==} dependencies: '@plotly/d3': 3.8.1 '@plotly/d3-sankey': 0.7.2 @@ -6119,7 +6328,7 @@ packages: canvas-fit: 1.5.0 color-alpha: 1.0.4 color-normalize: 1.5.0 - color-parse: 1.3.8 + color-parse: 2.0.0 color-rgba: 2.1.1 country-regex: 1.1.0 d3-force: 1.2.1 @@ -6133,7 +6342,6 @@ packages: fast-isnumeric: 1.1.4 gl-mat4: 1.2.0 gl-text: 1.3.1 - glslify: 7.1.1 has-hover: 1.0.1 has-passive-events: 1.0.0 is-mobile: 4.0.0 @@ -6143,11 +6351,11 @@ packages: native-promise-only: 0.8.1 parse-svg-path: 0.1.2 point-in-polygon: 1.1.0 - polybooljs: 1.2.0 + polybooljs: 1.2.2 probe-image-size: 7.2.3 regl: /@plotly/regl@2.1.2 regl-error2d: 2.0.12 - regl-line2d: 3.1.2 + regl-line2d: 3.1.3 regl-scatter2d: 3.3.1 regl-splom: 1.0.14 strongly-connected-components: 1.0.1 @@ -6167,17 +6375,22 @@ packages: resolution: {integrity: sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==} dev: false - /polybooljs@1.2.0: - resolution: {integrity: sha512-mKjR5nolISvF+q2BtC1fi/llpxBPTQ3wLWN8+ldzdw2Hocpc8C72ZqnamCM4Z6z+68GVVjkeM01WJegQmZ8MEQ==} + /polybooljs@1.2.2: + resolution: {integrity: sha512-ziHW/02J0XuNuUtmidBc6GXE8YohYydp3DWPWXYsd7O721TjcmN+k6ezjdwkDqep+gnWnFY+yqZHvzElra2oCg==} dev: false - /postcss@8.4.35: - resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true + + /postcss@8.4.37: + resolution: {integrity: sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 picocolors: 1.0.0 - source-map-js: 1.0.2 + source-map-js: 1.2.0 dev: false /potpack@1.0.2: @@ -6286,8 +6499,8 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /react-hook-form@7.50.1(react@18.2.0): - resolution: {integrity: sha512-3PCY82oE0WgeOgUtIr3nYNNtNvqtJ7BZjsbxh6TnYNbXButaD5WpjOmTjdxZfheuHKR68qfeFnEDVYoSSFPMTQ==} + /react-hook-form@7.51.1(react@18.2.0): + resolution: {integrity: sha512-ifnBjl+kW0ksINHd+8C/Gp6a4eZOdWyvRv0UBaByShwU8JbVx5hTcTWEcd5VdybvmPTATkVVXk9npXArHmo56w==} engines: {node: '>=12.22.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 @@ -6302,14 +6515,14 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: false - /react-markdown@9.0.0(@types/react@18.2.55)(react@18.2.0): + /react-markdown@9.0.0(@types/react@18.2.67)(react@18.2.0): resolution: {integrity: sha512-v6yNf3AB8GfJ8lCpUvzxAXKxgsHpdmWPlcVRQ6Nocsezp255E/IDrF31kLQsPJeB/cKto/geUwjU36wH784FCA==} peerDependencies: '@types/react': '>=18' react: '>=18' dependencies: '@types/hast': 3.0.4 - '@types/react': 18.2.55 + '@types/react': 18.2.67 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.0 html-url-attributes: 3.0.0 @@ -6325,8 +6538,8 @@ packages: - supports-color dev: false - /react-pdf@7.7.0(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-704ObLnRDm5lixL4e6NXNLaincBHGNLo+NGdbO3rEXE963NlNzwLxFpmKcbdXHAMQL4rYJQWb1L0w5IL6y8Osw==} + /react-pdf@7.7.1(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-cbbf/PuRtGcPPw+HLhMI1f6NSka8OJgg+j/yPWTe95Owf0fK6gmVY7OXpTxMeh92O3T3K3EzfE0ML0eXPGwR5g==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6335,30 +6548,30 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.55 + '@types/react': 18.2.67 clsx: 2.1.0 dequal: 2.0.3 make-cancellable-promise: 1.3.2 make-event-props: 1.6.2 - merge-refs: 1.2.2(@types/react@18.2.55) + merge-refs: 1.2.2(@types/react@18.2.67) pdfjs-dist: 3.11.174 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 warning: 4.0.3 transitivePeerDependencies: - encoding - supports-color dev: false - /react-plotly.js@2.6.0(plotly.js@2.29.1)(react@18.2.0): + /react-plotly.js@2.6.0(plotly.js@2.30.1)(react@18.2.0): resolution: {integrity: sha512-g93xcyhAVCSt9kV1svqG1clAEdL6k3U+jjuSzfTV7owaSU9Go6Ph8bl25J+jKfKvIGAEYpe4qj++WHJuc9IaeA==} peerDependencies: plotly.js: '>1.34.0' react: '>0.13.0' dependencies: - plotly.js: 2.29.1(mapbox-gl@1.13.3) + plotly.js: 2.30.1(mapbox-gl@1.13.3) prop-types: 15.8.1 react: 18.2.0 dev: false @@ -6368,31 +6581,31 @@ packages: engines: {node: '>=0.10.0'} dev: false - /react-router-dom@6.22.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-z2w+M4tH5wlcLmH3BMMOMdrtrJ9T3oJJNsAlBJbwk+8Syxd5WFJ7J5dxMEW0/GEXD1BBis4uXRrNIz3mORr0ag==} + /react-router-dom@6.22.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' dependencies: - '@remix-run/router': 1.15.0 + '@remix-run/router': 1.15.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-router: 6.22.0(react@18.2.0) + react-router: 6.22.3(react@18.2.0) dev: false - /react-router@6.22.0(react@18.2.0): - resolution: {integrity: sha512-q2yemJeg6gw/YixRlRnVx6IRJWZD6fonnfZhN1JIOhV2iJCPeRNSH3V1ISwHf+JWcESzLC3BOLD1T07tmO5dmg==} + /react-router@6.22.3(react@18.2.0): + resolution: {integrity: sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' dependencies: - '@remix-run/router': 1.15.0 + '@remix-run/router': 1.15.3 react: 18.2.0 dev: false - /react-to-print@2.14.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-SKnwOzU2cJ8eaAkoJO7+gNhvfEDmm+Y34IdcHsjtHioUevUPhprqbVtvNJlZ2JkGJ8ExK2QNWM9pXECTDR5D8w==} + /react-to-print@2.15.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-1foogIFbCpzAVxydkhBiDfMiFYhIMphiagDOfcG4X/EcQ+fBPqJ0rby9Wv/emzY1YLkIQy/rEgOrWQT+rBKhjw==} peerDependencies: react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 @@ -6418,7 +6631,7 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.24.1 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -6433,18 +6646,18 @@ packages: loose-envify: 1.4.0 dev: false - /reactflow@11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-DGNrTdkWjZtPOhj5MV8fiWWGkJo+otMVdoJ9l67bQL+Xf+8NkJ4AHmRXoYIxtgcENzwTr5WTAIJlswV9i91cyw==} + /reactflow@11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-0CApYhtYicXEDg/x2kvUHiUk26Qur8lAtTtiSlptNKuyEuGti6P1y5cS32YGaUoDMoCqkm/m+jcKkfMOvSCVRA==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/background': 11.3.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/controls': 11.2.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/core': 11.10.3(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/minimap': 11.7.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/node-resizer': 2.2.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) - '@reactflow/node-toolbar': 1.3.8(@types/react@18.2.55)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/background': 11.3.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/controls': 11.2.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/core': 11.10.4(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/minimap': 11.7.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/node-resizer': 2.2.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) + '@reactflow/node-toolbar': 1.3.9(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: @@ -6491,13 +6704,13 @@ packages: picomatch: 2.3.1 dev: false - /reflect.getprototypeof@1.0.5: - resolution: {integrity: sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==} + /reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 es-errors: 1.3.0 get-intrinsic: 1.2.4 globalthis: 1.0.3 @@ -6524,7 +6737,7 @@ packages: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 - set-function-name: 2.0.1 + set-function-name: 2.0.2 dev: true /regl-error2d@2.0.12: @@ -6539,8 +6752,8 @@ packages: update-diff: 1.1.0 dev: false - /regl-line2d@3.1.2: - resolution: {integrity: sha512-nmT7WWS/WxmXAQMkgaMKWXaVmwJ65KCrjbqHGOUjjqQi6shfT96YbBOvelXwO9hG7/hjvbzjtQ2UO0L3e7YaXQ==} + /regl-line2d@3.1.3: + resolution: {integrity: sha512-fkgzW+tTn4QUQLpFKsUIE0sgWdCmXAM3ctXcCgoGBZTSX5FE2A0M7aynz7nrZT5baaftLrk9te54B+MEq4QcSA==} dependencies: array-bounds: 1.0.1 array-find-index: 1.0.2 @@ -6549,7 +6762,6 @@ packages: earcut: 2.2.4 es6-weak-map: 2.0.3 flatten-vertex-data: 1.0.2 - glslify: 7.1.1 object-assign: 4.1.1 parse-rect: 1.2.0 pick-by-alias: 1.2.0 @@ -6726,26 +6938,26 @@ packages: dependencies: glob: 7.2.3 - /rollup@4.10.0: - resolution: {integrity: sha512-t2v9G2AKxcQ8yrG+WGxctBes1AomT0M4ND7jTFBCVPXQ/WFTvNSefIrNSmLKhIKBrvN8SG+CZslimJcT3W2u2g==} + /rollup@4.13.0: + resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.10.0 - '@rollup/rollup-android-arm64': 4.10.0 - '@rollup/rollup-darwin-arm64': 4.10.0 - '@rollup/rollup-darwin-x64': 4.10.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.10.0 - '@rollup/rollup-linux-arm64-gnu': 4.10.0 - '@rollup/rollup-linux-arm64-musl': 4.10.0 - '@rollup/rollup-linux-riscv64-gnu': 4.10.0 - '@rollup/rollup-linux-x64-gnu': 4.10.0 - '@rollup/rollup-linux-x64-musl': 4.10.0 - '@rollup/rollup-win32-arm64-msvc': 4.10.0 - '@rollup/rollup-win32-ia32-msvc': 4.10.0 - '@rollup/rollup-win32-x64-msvc': 4.10.0 + '@rollup/rollup-android-arm-eabi': 4.13.0 + '@rollup/rollup-android-arm64': 4.13.0 + '@rollup/rollup-darwin-arm64': 4.13.0 + '@rollup/rollup-darwin-x64': 4.13.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.13.0 + '@rollup/rollup-linux-arm64-gnu': 4.13.0 + '@rollup/rollup-linux-arm64-musl': 4.13.0 + '@rollup/rollup-linux-riscv64-gnu': 4.13.0 + '@rollup/rollup-linux-x64-gnu': 4.13.0 + '@rollup/rollup-linux-x64-musl': 4.13.0 + '@rollup/rollup-win32-arm64-msvc': 4.13.0 + '@rollup/rollup-win32-ia32-msvc': 4.13.0 + '@rollup/rollup-win32-x64-msvc': 4.13.0 fsevents: 2.3.3 dev: false @@ -6759,8 +6971,8 @@ packages: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} dev: false - /safe-array-concat@1.1.0: - resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} dependencies: call-bind: 1.0.7 @@ -6823,8 +7035,8 @@ packages: dev: false optional: true - /set-function-length@1.2.1: - resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 @@ -6835,11 +7047,12 @@ packages: has-property-descriptors: 1.0.2 dev: true - /set-function-name@2.0.1: - resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 + es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 dev: true @@ -6858,8 +7071,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - /side-channel@1.0.5: - resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -6911,8 +7124,8 @@ packages: tslib: 2.6.2 dev: false - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} dev: false @@ -6983,30 +7196,31 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.22.5 get-intrinsic: 1.2.4 has-symbols: 1.0.3 internal-slot: 1.0.7 regexp.prototype.flags: 1.5.2 - set-function-name: 2.0.1 - side-channel: 1.0.5 + set-function-name: 2.0.2 + side-channel: 1.0.6 dev: true - /string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 + es-object-atoms: 1.0.0 dev: true - /string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-object-atoms: 1.0.0 dev: true /string.prototype.trimstart@1.0.7: @@ -7014,7 +7228,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.2 dev: true /string_decoder@0.10.31: @@ -7134,8 +7348,8 @@ packages: svg-path-bounds: 1.0.2 dev: false - /swr@2.2.4(react@18.2.0): - resolution: {integrity: sha512-njiZ/4RiIhoOlAaLYDqwz5qH/KZXVilRLvomrx83HjzCWTfa+InyfAjv05PSFxnmLzZkNO9ZfvgoqzAaEI4sGQ==} + /swr@2.2.5(react@18.2.0): + resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==} peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 dependencies: @@ -7193,8 +7407,8 @@ packages: resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} dev: false - /tiny-invariant@1.3.1: - resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} + /tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} dev: false /tinycolor2@1.6.0: @@ -7251,17 +7465,17 @@ packages: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} dev: false - /ts-api-utils@1.2.1(typescript@5.3.3): - resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} + /ts-api-utils@1.3.0(typescript@5.4.2): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.3.3 + typescript: 5.4.2 dev: true - /tsconfck@3.0.2(typescript@5.3.3): - resolution: {integrity: sha512-6lWtFjwuhS3XI4HsX4Zg0izOI3FU/AI9EGVlPEUMDIhvLPMD4wkiof0WCoDgW7qY+Dy198g4d9miAqUHWHFH6Q==} + /tsconfck@3.0.3(typescript@5.4.2): + resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} engines: {node: ^18 || >=20} hasBin: true peerDependencies: @@ -7270,7 +7484,7 @@ packages: typescript: optional: true dependencies: - typescript: 5.3.3 + typescript: 5.4.2 dev: false /tsconfig-paths@3.15.0: @@ -7289,14 +7503,14 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - /tsutils@3.21.0(typescript@5.3.3): + /tsutils@3.21.0(typescript@5.4.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 5.3.3 + typescript: 5.4.2 dev: true /type-check@0.4.0: @@ -7316,16 +7530,12 @@ packages: engines: {node: '>=12.20'} dev: false - /type@1.2.0: - resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} - dev: false - /type@2.7.2: resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} dev: false - /typed-array-buffer@1.0.1: - resolution: {integrity: sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==} + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -7333,33 +7543,39 @@ packages: is-typed-array: 1.1.13 dev: true - /typed-array-byte-length@1.0.0: - resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 for-each: 0.3.3 - has-proto: 1.0.1 + gopd: 1.0.1 + has-proto: 1.0.3 is-typed-array: 1.1.13 dev: true - /typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.6 + available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 - has-proto: 1.0.1 + gopd: 1.0.1 + has-proto: 1.0.3 is-typed-array: 1.1.13 dev: true - /typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + /typed-array-length@1.0.5: + resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 dev: true /typedarray-pool@1.2.0: @@ -7373,8 +7589,8 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: false - /typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + /typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} engines: {node: '>=14.17'} hasBin: true @@ -7492,8 +7708,9 @@ packages: unist-util-visit-parents: 6.0.1 dev: false - /unplugin@1.7.1: - resolution: {integrity: sha512-JqzORDAPxxs8ErLV4x+LL7bk5pk3YlcWqpSNsIkAZj972KzFZLClc/ekppahKkOczGkwIG6ElFgdOgOlK4tXZw==} + /unplugin@1.10.0: + resolution: {integrity: sha512-CuZtvvO8ua2Wl+9q2jEaqH6m3DoQ38N7pvBYQbbaeNlWGvK2l6GHiKi29aIHDPoSxdUzQ7Unevf1/ugil5X6Pg==} + engines: {node: '>=14.0.0'} dependencies: acorn: 8.11.3 chokidar: 3.6.0 @@ -7505,13 +7722,13 @@ packages: resolution: {integrity: sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==} dev: false - /update-browserslist-db@1.0.13(browserslist@4.22.3): + /update-browserslist-db@1.0.13(browserslist@4.23.0): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.22.3 + browserslist: 4.23.0 escalade: 3.1.2 picocolors: 1.0.0 dev: false @@ -7581,23 +7798,23 @@ packages: vfile-message: 4.0.2 dev: false - /vite-plugin-svgr@4.2.0(typescript@5.3.3)(vite@5.1.1): + /vite-plugin-svgr@4.2.0(typescript@5.4.2)(vite@5.1.6): resolution: {integrity: sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==} peerDependencies: vite: ^2.6.0 || 3 || 4 || 5 dependencies: '@rollup/pluginutils': 5.1.0 - '@svgr/core': 8.1.0(typescript@5.3.3) + '@svgr/core': 8.1.0(typescript@5.4.2) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) - vite: 5.1.1 + vite: 5.1.6 transitivePeerDependencies: - rollup - supports-color - typescript dev: false - /vite-tsconfig-paths@4.3.1(typescript@5.3.3)(vite@5.1.1): - resolution: {integrity: sha512-cfgJwcGOsIxXOLU/nELPny2/LUD/lcf1IbfyeKTv2bsupVbTH/xpFtdQlBmIP1GEK2CjjLxYhFfB+QODFAx5aw==} + /vite-tsconfig-paths@4.3.2(typescript@5.4.2)(vite@5.1.6): + resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: vite: '*' peerDependenciesMeta: @@ -7606,15 +7823,15 @@ packages: dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.2(typescript@5.3.3) - vite: 5.1.1 + tsconfck: 3.0.3(typescript@5.4.2) + vite: 5.1.6 transitivePeerDependencies: - supports-color - typescript dev: false - /vite@5.1.1: - resolution: {integrity: sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==} + /vite@5.1.6: + resolution: {integrity: sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -7642,8 +7859,8 @@ packages: optional: true dependencies: esbuild: 0.19.12 - postcss: 8.4.35 - rollup: 4.10.0 + postcss: 8.4.37 + rollup: 4.13.0 optionalDependencies: fsevents: 2.3.3 dev: false @@ -7728,24 +7945,25 @@ packages: is-weakref: 1.0.2 isarray: 2.0.5 which-boxed-primitive: 1.0.2 - which-collection: 1.0.1 - which-typed-array: 1.1.14 + which-collection: 1.0.2 + which-typed-array: 1.1.15 dev: true - /which-collection@1.0.1: - resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} dependencies: - is-map: 2.0.2 - is-set: 2.0.2 - is-weakmap: 2.0.1 - is-weakset: 2.0.2 + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 dev: true - /which-typed-array@1.1.14: - resolution: {integrity: sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==} + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.6 + available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 @@ -7821,8 +8039,8 @@ packages: engines: {node: '>=10'} dev: true - /yup@1.3.3: - resolution: {integrity: sha512-v8QwZSsHH2K3/G9WSkp6mZKO+hugKT1EmnMqLNUcfu51HU9MDyhlETT/JgtzprnrnQHPWsjc6MUDMBp/l9fNnw==} + /yup@1.4.0: + resolution: {integrity: sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==} dependencies: property-expr: 2.0.6 tiny-case: 1.0.3 @@ -7830,8 +8048,8 @@ packages: type-fest: 2.19.0 dev: false - /zustand@4.5.0(@types/react@18.2.55)(react@18.2.0): - resolution: {integrity: sha512-zlVFqS5TQ21nwijjhJlx4f9iGrXSL0o/+Dpy4txAP22miJ8Ti6c1Ol1RLNN98BMib83lmDH/2KmLwaNXpjrO1A==} + /zustand@4.5.2(@types/react@18.2.67)(react@18.2.0): + resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==} engines: {node: '>=12.7.0'} peerDependencies: '@types/react': '>=16.8' @@ -7845,7 +8063,7 @@ packages: react: optional: true dependencies: - '@types/react': 18.2.55 + '@types/react': 18.2.67 react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) dev: false diff --git a/frontend/src/@types/general/index.d.ts b/frontend/src/@types/general/index.d.ts new file mode 100644 index 00000000..78f081f1 --- /dev/null +++ b/frontend/src/@types/general/index.d.ts @@ -0,0 +1,6 @@ +interface PaginationMetadata { + page: number; + records: number; + total: number; + last_page: number; +} diff --git a/frontend/src/@types/global.d.ts b/frontend/src/@types/global.d.ts index cf982313..a86a367f 100644 --- a/frontend/src/@types/global.d.ts +++ b/frontend/src/@types/global.d.ts @@ -1,3 +1,3 @@ /* eslint-disable @typescript-eslint/triple-slash-reference */ /// -/// +/// diff --git a/frontend/src/@types/utils/index.d.ts b/frontend/src/@types/utils/index.d.ts deleted file mode 100644 index 3b088b25..00000000 --- a/frontend/src/@types/utils/index.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -declare global { - type FunctionOrPromiseReturnType = T extends ( - instance: ReactFlowInstance, - ) => infer R - ? R - : T extends ( - instance: ReactFlowInstance, - ) => Promise - ? R - : never; -} - -export {}; diff --git a/frontend/src/components/DatetimeInput/index.tsx b/frontend/src/components/DatetimeInput/index.tsx index 49ff264f..504eb5df 100644 --- a/frontend/src/components/DatetimeInput/index.tsx +++ b/frontend/src/components/DatetimeInput/index.tsx @@ -67,7 +67,9 @@ function DatetimeInput({ textField: { error: !!error, helperText: ( - {error?.message} + + {error?.message} + ), }, }} @@ -109,7 +111,9 @@ function DatetimeInput({ textField: { error: !!error, helperText: ( - {error?.message} + + {error?.message} + ), }, }} @@ -153,7 +157,9 @@ function DatetimeInput({ textField: { error: !!error, helperText: ( - {error?.message} + + {error?.message} + ), }, }} diff --git a/frontend/src/components/PrivateLayout/header/drawerMenu.tsx b/frontend/src/components/PrivateLayout/header/drawerMenu.tsx index 2f0b496e..60db29b3 100644 --- a/frontend/src/components/PrivateLayout/header/drawerMenu.tsx +++ b/frontend/src/components/PrivateLayout/header/drawerMenu.tsx @@ -49,7 +49,7 @@ export const DrawerMenu: FC = ({ isOpen, handleClose }) => { {theme.direction === "rtl" ? : } logo @@ -63,13 +63,11 @@ export const DrawerMenu: FC = ({ isOpen, handleClose }) => { alignItems: "center", display: { xs: "none", md: "flex" }, }} - onClick={ - () => { - if (workspace) { - navigate("/workspace-settings"); - } - } /* go to selected workspace setting */ - } + onClick={() => { + if (workspace) { + navigate("/workspaces/settings"); + } + }} > = ({ isOpen, handleClose }) => { { - navigate("/profile"); + // navigate("/profile"); }} icon={} label={"Profile"} diff --git a/frontend/src/components/PrivateLayout/index.tsx b/frontend/src/components/PrivateLayout/index.tsx index 0e4e3d9b..fc8f710d 100644 --- a/frontend/src/components/PrivateLayout/index.tsx +++ b/frontend/src/components/PrivateLayout/index.tsx @@ -3,12 +3,11 @@ import { type FC, type ReactNode } from "react"; import { Header } from "./header/header"; -interface IPrivateLayoutProps { +interface Props { children: ReactNode; - sidePanel?: ReactNode; } -export const PrivateLayout: FC = ({ children }) => { +export const PrivateLayout: FC = ({ children }) => { return (
diff --git a/frontend/src/components/RoleComponent/index.tsx b/frontend/src/components/RoleComponent/index.tsx new file mode 100644 index 00000000..378d3cef --- /dev/null +++ b/frontend/src/components/RoleComponent/index.tsx @@ -0,0 +1,21 @@ +import { useWorkspaces } from "@context/workspaces"; +import { type Roles } from "@utils/roles"; +import React, { type ReactNode } from "react"; + +interface IProps { + children?: ReactNode; + allowedRoles: Roles[]; +} + +export const RequireRoleComponent: React.FC = ({ + allowedRoles, + children, +}) => { + const { workspace } = useWorkspaces(); + + const authorized = allowedRoles.some( + (item) => workspace?.user_permission === item, + ); + + return authorized ? <>{children} :
Not authorized
; +}; diff --git a/frontend/src/components/Routes/AuthorizationRoute/index.tsx b/frontend/src/components/Routes/AuthorizationRoute/index.tsx new file mode 100644 index 00000000..c9106aae --- /dev/null +++ b/frontend/src/components/Routes/AuthorizationRoute/index.tsx @@ -0,0 +1,77 @@ +import { useWorkspaces } from "@context/workspaces"; +import { type Roles } from "@utils/roles"; +import React, { type ReactNode } from "react"; +import { Navigate } from "react-router-dom"; + +type Props = { + children?: ReactNode; +} & { + requireWorkspace?: boolean; + allowedRoles?: Roles[]; +}; + +/** + * Component for authorization routing. + * @returns {React.ReactElement} - JSX for authorization routing. + * @example Example usage: + * + * + * + * @description Truth Table: + * | requireWorkspace | allowedRoles.length | workspace | Result | + * |------------------|---------------------|-----------|---------------------------| + * | false | 0 | null | Render children | + * | false | 0 | not null | Redirect to unauthorized | + * | false | > 0 | null | Redirect to workspaces | + * | false | > 0 | not null | Check permission | + * | true | 0 | null | Redirect to workspaces | + * | true | 0 | not null | Render children | + * | true | > 0 | null | Redirect to workspaces | + * | true | > 0 | not null | Check permission | + */ +export const AuthorizationRoute = ({ + requireWorkspace = false, + allowedRoles = [], + children, +}: Props): React.ReactElement => { + const { workspace } = useWorkspaces(); + + // Redirect if workspace is required but not available + if (requireWorkspace && !workspace) { + return ; + } + + // Redirect if no workspace but allowed roles specified + if (!requireWorkspace && allowedRoles.length > 0 && !workspace) { + return ; + } + + // No workspace required and no roles specified, render children + if (!requireWorkspace && allowedRoles.length === 0) { + return <>{children}; + } + + // Workspace required and no roles specified, render children + if (requireWorkspace && workspace && allowedRoles.length === 0) { + return <>{children}; + } + + // Check if the user has permission for allowed roles + if (workspace && allowedRoles.length > 0) { + const hasPermission = + workspace.user_permission && + allowedRoles.includes(workspace.user_permission); + + return hasPermission ? ( + <>{children} + ) : ( + + ); + } + + // Redirect to unauthorized if no other conditions met + return ; +}; diff --git a/frontend/src/components/Routes/NotFoundRoute/index.tsx b/frontend/src/components/Routes/NotFoundRoute/index.tsx new file mode 100644 index 00000000..735b815f --- /dev/null +++ b/frontend/src/components/Routes/NotFoundRoute/index.tsx @@ -0,0 +1,34 @@ +import { useAuthentication } from "@context/authentication"; +import { type ReactNode, type FC } from "react"; +import { Navigate, useLocation } from "react-router-dom"; + +export interface Props { + children?: ReactNode; +} + +export const NotFoundRoute: FC = () => { + const { isLogged } = useAuthentication(); + const { state } = useLocation(); + + if (isLogged) { + return state && state.from === "/" ? ( + <> + + + ) : ( + <> +

404 - Not Found

+ + ); + } else { + return state && state.from === "/" ? ( + <> + + + ) : ( + <> +

404 - Not Found

+ + ); + } +}; diff --git a/frontend/src/components/Routes/PrivateRoute/index.tsx b/frontend/src/components/Routes/PrivateRoute/index.tsx new file mode 100644 index 00000000..f9516683 --- /dev/null +++ b/frontend/src/components/Routes/PrivateRoute/index.tsx @@ -0,0 +1,25 @@ +import PrivateLayout from "@components/PrivateLayout"; +import { useAuthentication } from "@context/authentication"; +import { type FC, type ReactNode } from "react"; +import { Navigate, Outlet } from "react-router-dom"; + +interface Props { + children?: ReactNode; +} + +/** + * @returns PrivateRoute redirect to `/sign-in` if the user are NOT logged + */ +export const PrivateRoute: FC = () => { + const { isLogged } = useAuthentication(); + + if (!isLogged) { + return ; + } + + return ( + + + + ); +}; diff --git a/frontend/src/components/Routes/PublicRoute/index.tsx b/frontend/src/components/Routes/PublicRoute/index.tsx new file mode 100644 index 00000000..18533e80 --- /dev/null +++ b/frontend/src/components/Routes/PublicRoute/index.tsx @@ -0,0 +1,21 @@ +import { useAuthentication } from "context/authentication"; +import { type ReactNode, type FC } from "react"; +import { Navigate, Outlet } from "react-router-dom"; + +export interface Props { + children?: ReactNode; + /** + * `true` if this route is accessible only for not authenticated users + * @default false + * */ + publicOnly?: boolean; +} + +export const PublicRoute: FC = ({ publicOnly }) => { + const { isLogged } = useAuthentication(); + return publicOnly && isLogged ? ( + + ) : ( + + ); +}; diff --git a/frontend/src/components/Routes/index.ts b/frontend/src/components/Routes/index.ts new file mode 100644 index 00000000..a486dffe --- /dev/null +++ b/frontend/src/components/Routes/index.ts @@ -0,0 +1,2 @@ +export * from "./PrivateRoute"; +export * from "./AuthorizationRoute"; diff --git a/frontend/src/config/environment.config.ts b/frontend/src/config/environment.config.ts index f534c049..0bfde633 100644 --- a/frontend/src/config/environment.config.ts +++ b/frontend/src/config/environment.config.ts @@ -1,19 +1,7 @@ -/** - * @todo add other envs when available - */ -export type INodeEnv = "development"; - export interface IEnvironment { - NODE_ENV: INodeEnv; - USE_MOCK: boolean; API_URL: string; } -/** - * Stores all environment variables for easier access - */ export const environment: IEnvironment = { - NODE_ENV: import.meta.env.NODE_ENV as INodeEnv, API_URL: import.meta.env.API_URL as string, - USE_MOCK: !!import.meta.env.VITE_USE_MOCK, }; diff --git a/frontend/src/context/authentication/api/index.ts b/frontend/src/context/authentication/api/index.ts deleted file mode 100644 index 38581eea..00000000 --- a/frontend/src/context/authentication/api/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./postAuthLogin"; -export * from "./postAuthRegister"; diff --git a/frontend/src/context/authentication/api/postAuthLogin.ts b/frontend/src/context/authentication/api/postAuthLogin.ts deleted file mode 100644 index bbf42904..00000000 --- a/frontend/src/context/authentication/api/postAuthLogin.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface IPostAuthLoginParams { - email: string; - password: string; -} - -interface IPostAuthLoginResponseInterface { - user_id: string; - group_ids: number[]; - access_token: string; - token_expires_in: number; -} - -/** - * Authenticate the user using POST /auth/login - * @param params `{ email: string, password: string }` - * @returns access token - */ -export const postAuthLogin: ( - params: IPostAuthLoginParams, -) => Promise> = async ( - params, -) => { - return await dominoApiClient.post("/auth/login", params); -}; - -export const postAuthLoginMockResponse: IPostAuthLoginResponseInterface = { - user_id: "some_id", - group_ids: [0], - access_token: "MOCK ACCESS TOKEN", - token_expires_in: new Date().getTime() + 10000, -}; diff --git a/frontend/src/context/authentication/api/postAuthRegister.ts b/frontend/src/context/authentication/api/postAuthRegister.ts deleted file mode 100644 index d5b875d0..00000000 --- a/frontend/src/context/authentication/api/postAuthRegister.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface IPostAuthRegisterParams { - email: string; - password: string; -} - -interface IPostAuthRegisterResponseInterface { - user_id: string; - email: string; - token_expires_in: number; - groups: Array<{ group_id: number; group_name: string }>; -} - -/** - * Authenticate the user using POST /auth/register - * @param params `{ email: string, password: string }` - * @returns access token - */ -export const postAuthRegister: ( - params: IPostAuthRegisterParams, -) => Promise> = async ( - params, -) => { - return await dominoApiClient.post("/auth/register", params); -}; - -export const postAuthRegisterMockResponse: IPostAuthRegisterResponseInterface = - { - user_id: "some_id", - email: "some@email.com", - token_expires_in: 3600, - groups: [{ group_id: 0, group_name: "some group" }], - }; diff --git a/frontend/src/context/authentication/authentication.context.tsx b/frontend/src/context/authentication/authentication.context.tsx index a5f2d775..4dc5a480 100644 --- a/frontend/src/context/authentication/authentication.context.tsx +++ b/frontend/src/context/authentication/authentication.context.tsx @@ -1,3 +1,4 @@ +import { useAuthLogin, useAuthRegister } from "@features/auth"; import React, { type ReactNode, useCallback, @@ -10,7 +11,6 @@ import { useNavigate } from "react-router-dom"; import { toast } from "react-toastify"; import { createCustomContext } from "utils"; -import { postAuthLogin, postAuthRegister } from "./api"; import { type IAuthenticationContext, type IAuthenticationStore, @@ -20,10 +20,6 @@ import { DOMINO_LOGOUT } from "./authentication.logout"; export const [AuthenticationContext, useAuthentication] = createCustomContext("Authentication Context"); -/** - * Authentication provider. - * @todo refactor local storage implementation with Local Forage - */ export const AuthenticationProvider: React.FC<{ children: ReactNode }> = ({ children, }) => { @@ -34,6 +30,9 @@ export const AuthenticationProvider: React.FC<{ children: ReactNode }> = ({ userId: localStorage.getItem("userId"), }); + const { mutateAsync: postAuthLogin } = useAuthLogin(); + const { mutateAsync: postAuthRegister } = useAuthRegister(); + const isLogged = useRef(!!store.token); const login = useCallback( @@ -73,15 +72,14 @@ export const AuthenticationProvider: React.FC<{ children: ReactNode }> = ({ const authenticate = useCallback( async (email: string, password: string) => { setAuthLoading(true); - void postAuthLogin({ email, password }) + await postAuthLogin({ email, password }) .then((res) => { - if (res.status === 200) { - login( - res.data.access_token, - res.data.user_id, - res.data.token_expires_in, - ); - } + login( + res.access_token, + res.user_id, + res.token_expires_in, + "/workspaces", + ); }) .finally(() => { setAuthLoading(false); @@ -95,18 +93,13 @@ export const AuthenticationProvider: React.FC<{ children: ReactNode }> = ({ setAuthLoading(true); postAuthRegister({ email, password }) .then((res) => { - if (res.status === 201) { + if (res?.user_id) { toast.success("E-mail and password registered successfully!"); void authenticate(email, password); } }) .catch((err) => { - console.log(err?.response?.status); - if (err?.response?.status === 409) { - toast.warning(`This e-mail is already registered`); - } else { - toast.error(err?.response?.data?.detail ?? `Error while register`); - } + console.error(err?.response); }) .finally(() => { setAuthLoading(false); diff --git a/frontend/src/context/workspaces/api/acceptWorkspaceInvite.ts b/frontend/src/context/workspaces/api/acceptWorkspaceInvite.ts deleted file mode 100644 index 14f509a7..00000000 --- a/frontend/src/context/workspaces/api/acceptWorkspaceInvite.ts +++ /dev/null @@ -1,34 +0,0 @@ -// TODO move to /runs -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface AcceptWorkspaceInviteParams { - workspaceId: string; -} - -const acceptWorkspaceInviteUrl = (workspaceId: string) => - `/workspaces/${workspaceId}/invites/accept`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const acceptWorkspaceInvite: ( - params: AcceptWorkspaceInviteParams, -) => Promise = async (params) => { - return await dominoApiClient.post( - acceptWorkspaceInviteUrl(params.workspaceId), - null, - ); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedAcceptWorkspaceInvite = () => { - const fetcher = async (params: AcceptWorkspaceInviteParams) => - await acceptWorkspaceInvite(params).then((data) => data); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/api/deleteUserWorkspace.ts b/frontend/src/context/workspaces/api/deleteUserWorkspace.ts deleted file mode 100644 index a783e657..00000000 --- a/frontend/src/context/workspaces/api/deleteUserWorkspace.ts +++ /dev/null @@ -1,34 +0,0 @@ -// TODO move to /runs -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface RemoveUserWorkspaceParams { - workspaceId: string; - userId: string; -} - -const removeUserWorkspaceUrl = (workspaceId: string, userId: string) => - `/workspaces/${workspaceId}/users/${userId}`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const removeUserWorkspace: ( - params: RemoveUserWorkspaceParams, -) => Promise = async (params) => { - return await dominoApiClient.delete( - removeUserWorkspaceUrl(params.workspaceId, params.userId), - ); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedRemoveUserWorkspace = () => { - const fetcher = async (params: RemoveUserWorkspaceParams) => - await removeUserWorkspace(params).then((data) => data); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/api/deleteWorkspace.ts b/frontend/src/context/workspaces/api/deleteWorkspace.ts deleted file mode 100644 index 99d60ac4..00000000 --- a/frontend/src/context/workspaces/api/deleteWorkspace.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useCallback } from "react"; -import { dominoApiClient } from "services/clients/domino.client"; - -type IDeleteWorkspacesResponseInterface = unknown; - -export interface IDeleteWorkspacesParams { - id: string; -} - -/** - * Delete workspace using delete /workspaces/:id - * @returns ? - */ -const deleteWorkspace: ( - params: IDeleteWorkspacesParams, -) => Promise> = async ( - params, -) => { - return await dominoApiClient.delete(`/workspaces/${params.id}`); -}; - -export const useAuthenticatedDeleteWorkspaces = () => { - const fetcher = useCallback( - async (params: IDeleteWorkspacesParams) => - await deleteWorkspace(params).then((data) => { - return data; - }), - [], - ); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/api/getWorkspaceId.ts b/frontend/src/context/workspaces/api/getWorkspaceId.ts deleted file mode 100644 index 33a69b72..00000000 --- a/frontend/src/context/workspaces/api/getWorkspaceId.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -import { type IGetWorkspaceIdResponseInterface } from "../types/workspaces"; - -interface IGetWorkspaceIdParams { - id: string; -} - -/** - * Get workspaces using GET /workspaces/ - * @param id workspace id - * @returns workspace - */ -const getWorkspaceId: ( - params: IGetWorkspaceIdParams, -) => Promise> = async ( - params, -) => { - return await dominoApiClient.get(`/workspaces/${params.id}`); -}; - -/** - * Authenticated fetcher function that gets workspace by id - * @param params `{ id: string }` - * @returns workspace fetcher fn - */ -export const useAuthenticatedGetWorkspaceIdFetcher = () => { - return async (params: IGetWorkspaceIdParams) => - await getWorkspaceId(params).then((data) => data.data); -}; - -/** - * Get workspace data - * @returns workspace data as swr response - */ -export const useAuthenticatedGetWorkspace = (params: IGetWorkspaceIdParams) => { - const fetcher = useAuthenticatedGetWorkspaceIdFetcher(); - return useSWR(`/workspaces/${params.id}`, async () => await fetcher(params), { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }); -}; diff --git a/frontend/src/context/workspaces/api/getWorkspaceMembers.ts b/frontend/src/context/workspaces/api/getWorkspaceMembers.ts deleted file mode 100644 index 2493041f..00000000 --- a/frontend/src/context/workspaces/api/getWorkspaceMembers.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useAuthentication } from "context/authentication"; -import { useCallback } from "react"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -import { type IGetWorkspaceUsersResponse } from "../types/workspaces"; - -interface IGetWorkspaceMembers { - workspaceId: string; - page: number; - pageSize: number; -} - -const getWorkspaceUsersUrl = ( - auth: boolean, - workspaceId: string, - page: number, - pageSize: number, -) => { - // TODO: get workspaceId from context - this is a temporary solution - const workspace = localStorage.getItem("workspace"); - return auth && workspaceId && workspace - ? `/workspaces/${workspaceId}/users?page=${page}&page_size=${pageSize}` - : null; -}; - -/** - * Get workspaces using GET /workspaces - * @returns workspaces - */ -const getWorkspaceUsers: ( - auth: boolean, - workspaceId: string, - page: number, - pageSize: number, -) => Promise | undefined> = async ( - auth, - workspaceId, - page, - pageSize, -) => { - if (auth && workspaceId && !isNaN(page) && !isNaN(pageSize)) { - const url = getWorkspaceUsersUrl(auth, workspaceId, page, pageSize); - - if (url) return await dominoApiClient.get(url); - } -}; - -/** - * Get workspaces - * @returns workspaces as swr response - */ -export const useAuthenticatedGetWorkspaceUsers = ( - params: IGetWorkspaceMembers, -) => { - if (!params.page) { - params.page = 0; - } - if (!params.pageSize) { - params.pageSize = 10; - } - - const auth = useAuthentication(); - - const fetcher = useCallback(async () => { - return await getWorkspaceUsers( - auth.isLogged, - params.workspaceId, - params.page, - params.pageSize, - ).then((data) => data?.data); - }, [params]); - - return useSWR( - getWorkspaceUsersUrl( - auth.isLogged, - params.workspaceId, - params.page, - params.pageSize, - ), - fetcher, - ); -}; diff --git a/frontend/src/context/workspaces/api/getWorkspaces.ts b/frontend/src/context/workspaces/api/getWorkspaces.ts deleted file mode 100644 index e0f7805a..00000000 --- a/frontend/src/context/workspaces/api/getWorkspaces.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useAuthentication } from "context/authentication"; -import { useCallback } from "react"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -import { type IGetWorkspacesResponseInterface } from "../types/workspaces"; - -/** - * Get workspaces using GET /workspaces - * @returns workspaces - */ -const getWorkspaces: () => Promise< - AxiosResponse -> = async () => { - return await dominoApiClient.get("/workspaces"); -}; - -/** - * Get workspaces - * @returns workspaces as swr response - */ -export const useAuthenticatedGetWorkspaces = () => { - const fetcher = useCallback(async () => { - return await getWorkspaces().then((data) => data.data); - }, []); - - const auth = useAuthentication(); - - return useSWR( - auth.isLogged ? `/workspaces` : null, - async () => await fetcher(), - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }, - ); -}; diff --git a/frontend/src/context/workspaces/api/index.ts b/frontend/src/context/workspaces/api/index.ts deleted file mode 100644 index 4ea560e5..00000000 --- a/frontend/src/context/workspaces/api/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from "./getWorkspaceId"; -export * from "./getWorkspaces"; -export * from "./postPiecesRepositories"; -export * from "./postWorkspaces"; -export * from "./deleteWorkspace"; -export * from "./patchWorkspace"; -export * from "./acceptWorkspaceInvite"; -export * from "./rejectWorkspaceInvite"; -export * from "./inviteWorkspace"; -export * from "./deleteUserWorkspace"; -export * from "./getWorkspaceMembers"; diff --git a/frontend/src/context/workspaces/api/inviteWorkspace.ts b/frontend/src/context/workspaces/api/inviteWorkspace.ts deleted file mode 100644 index 577279cc..00000000 --- a/frontend/src/context/workspaces/api/inviteWorkspace.ts +++ /dev/null @@ -1,36 +0,0 @@ -// TODO move to /runs -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface InviteWorkspaceParams { - workspaceId: string; - userEmail: string; - permission: string; -} - -const inviteWorkspaceUrl = (workspaceId: string) => - `/workspaces/${workspaceId}/invites`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const inviteWorkspace: ( - params: InviteWorkspaceParams, -) => Promise = async (params) => { - return await dominoApiClient.post(inviteWorkspaceUrl(params.workspaceId), { - user_email: params.userEmail, - permission: params.permission, - }); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedWorkspaceInvite = () => { - const fetcher = async (params: InviteWorkspaceParams) => - await inviteWorkspace(params).then((data) => data); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/api/patchWorkspace.ts b/frontend/src/context/workspaces/api/patchWorkspace.ts deleted file mode 100644 index 9a7b77d7..00000000 --- a/frontend/src/context/workspaces/api/patchWorkspace.ts +++ /dev/null @@ -1,42 +0,0 @@ -// TODO move to /runs -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface PatchWorkspaceParams { - workspaceId: string; - payload: { - name?: string | null; - github_access_token?: string | null; - }; -} - -const patchWorkspaceUrl = (workspaceId: string) => `/workspaces/${workspaceId}`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const patchWorkspace: ( - params: PatchWorkspaceParams, -) => Promise = async (params) => { - return await dominoApiClient.patch( - patchWorkspaceUrl(params.workspaceId), - params.payload, - ); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedPatchWorkspace = () => { - const { workspace } = useWorkspaces(); - - if (!workspace) return async (_params: PatchWorkspaceParams) => {}; - - const fetcher = async (params: PatchWorkspaceParams) => - await patchWorkspace(params).then((data) => data); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/api/postPiecesRepositories.ts b/frontend/src/context/workspaces/api/postPiecesRepositories.ts deleted file mode 100644 index ec0d9c7f..00000000 --- a/frontend/src/context/workspaces/api/postPiecesRepositories.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; - -import { - type IPostWorkspaceRepositoryParams, - type IPostWorkspaceRepositoryPayload, - type IPostWorkspaceRepositoryResponseInterface, -} from "../types/workspaces"; - -/** - * Create workspacesidPiecesrepositories using POST /workspacesidPiecesrepositories - * @returns ? - */ -const postPiecesRepository: ( - params: IPostWorkspaceRepositoryParams, -) => Promise> = async ( - params, -) => { - return await dominoApiClient.post("/pieces-repositories", params.data); -}; - -/** - * Create authenticated workspacesidPiecesrepositories - * @param params `{ id: string, data: Record }`` - * @returns crate workspacesidPiecesrepositories function - */ -export const useAuthenticatedPostPiecesRepository = (params: { - workspace: string; -}) => { - if (!params?.workspace) - return async (_params: IPostWorkspaceRepositoryPayload) => {}; - - const fetcher = async (payload: IPostWorkspaceRepositoryPayload) => - await postPiecesRepository({ - id: params.workspace, - data: payload, - }).then((data) => data.data); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/api/postWorkspaces.ts b/frontend/src/context/workspaces/api/postWorkspaces.ts deleted file mode 100644 index cdb12f69..00000000 --- a/frontend/src/context/workspaces/api/postWorkspaces.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useCallback } from "react"; -import { dominoApiClient } from "services/clients/domino.client"; - -type IPostWorkspacesResponseInterface = Record; - -export interface IPostWorkspacesParams { - name: string; -} - -/** - * Create workspace using POST /workspaces - * @returns ? - */ -const postWorkspaces: ( - params: IPostWorkspacesParams, -) => Promise> = async ( - params, -) => { - return await dominoApiClient.post(`/workspaces`, params); -}; - -/** - * Create authenticated workspaces - * @param params `{ name: string }` - * @returns crate workspaces function - */ -export const useAuthenticatedPostWorkspaces = () => { - const fetcher = useCallback( - async (params: IPostWorkspacesParams) => - await postWorkspaces(params).then((data) => { - return data.data; - }), - [], - ); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/api/rejectWorkspaceInvite.ts b/frontend/src/context/workspaces/api/rejectWorkspaceInvite.ts deleted file mode 100644 index 132398e5..00000000 --- a/frontend/src/context/workspaces/api/rejectWorkspaceInvite.ts +++ /dev/null @@ -1,34 +0,0 @@ -// TODO move to /runs -import { type AxiosResponse } from "axios"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface RejectWorkspaceInviteParams { - workspaceId: string; -} - -const rejectWorkspaceInviteUrl = (workspaceId: string) => - `/workspaces/${workspaceId}/invites/reject`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const rejectWorkspaceInvite: ( - params: RejectWorkspaceInviteParams, -) => Promise = async (params) => { - return await dominoApiClient.post( - rejectWorkspaceInviteUrl(params.workspaceId), - null, - ); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedRejectWorkspaceInvite = () => { - const fetcher = async (params: RejectWorkspaceInviteParams) => - await rejectWorkspaceInvite(params).then((data) => data); - - return fetcher; -}; diff --git a/frontend/src/context/workspaces/repositories.tsx b/frontend/src/context/workspaces/repositories.tsx index f1d91107..e5b5f3c1 100644 --- a/frontend/src/context/workspaces/repositories.tsx +++ b/frontend/src/context/workspaces/repositories.tsx @@ -1,24 +1,20 @@ +import { useQueryClient } from "@tanstack/react-query"; import { useStorage } from "context/storage/useStorage"; import { - type IGetRepoPiecesResponseInterface, - useAuthenticatedGetPieceRepositories, - useFetchAuthenticatedGetRepoIdPieces, - type IGetPiecesRepositoriesResponseInterface, - type IGetPiecesRepositoriesReleasesParams, - type IGetPiecesRepositoriesReleasesResponseInterface, - useAuthenticatedGetPieceRepositoriesReleases, - useAuthenticatedDeleteRepository, -} from "features/myWorkflows/api"; -import React, { useCallback, useEffect, useState } from "react"; + useRepositories, + useRepositoriesReleases, + useAddRepository, + useDeleteRepository, + usePieces, + type AddRepositoryParams, + type AddRepositoryResponse, + type RepositoriesReleasesParams, + type RepositoriesReleasesResponse, +} from "features/workspaces/api"; +import React, { useCallback, useMemo, useState } from "react"; import { toast } from "react-toastify"; -import { type KeyedMutator } from "swr"; import { createCustomContext } from "utils"; -import { useAuthenticatedPostPiecesRepository } from "./api"; -import { - type IPostWorkspaceRepositoryPayload, - type IPostWorkspaceRepositoryResponseInterface, -} from "./types"; import { useWorkspaces } from "./workspaces"; export interface IPiecesContext { @@ -27,25 +23,21 @@ export interface IPiecesContext { repositoryPieces: PiecesRepository; repositoriesLoading: boolean; - selectedRepositoryId: null | number; - setSelectedRepositoryId: React.Dispatch>; - - handleRefreshRepositories: KeyedMutator< - IGetPiecesRepositoriesResponseInterface | undefined + selectedRepositoryId?: number; + setSelectedRepositoryId: React.Dispatch< + React.SetStateAction >; + handleAddRepository: ( - params: Omit, - ) => Promise; + params: AddRepositoryParams, + ) => Promise; handleFetchRepoReleases: ( - params: IGetPiecesRepositoriesReleasesParams, - ) => Promise; + params: RepositoriesReleasesParams, + ) => Promise; - handleDeleteRepository: (id: string) => Promise; + handleDeleteRepository: (params: { id: string }) => Promise; - fetchRepoById: (params: { - id: string; - }) => Promise; fetchForagePieceById: (id: number) => Piece | undefined; } @@ -57,101 +49,86 @@ export const [PiecesContext, usesPieces] = const PiecesProvider: React.FC<{ children: React.ReactNode }> = ({ children, }) => { + const { workspace } = useWorkspaces(); const localStorage = useStorage(); const [selectedRepositoryId, setSelectedRepositoryId] = useState< - number | null - >(null); - const [repositoryPieces, setRepositoryPieces] = useState( - {}, - ); + number | undefined + >(); - const { workspace, handleRefreshWorkspaces } = useWorkspaces(); - - const fetchRepoById = useFetchAuthenticatedGetRepoIdPieces(); - - const { - data: repositories, - error: repositoriesError, - isValidating: repositoriesLoading, - mutate: handleRefreshRepositories, - } = useAuthenticatedGetPieceRepositories({}); - - useEffect(() => { - let active = true; - void loadRepositoriesPieces(); - return () => { - active = false; - }; - - async function loadRepositoriesPieces() { - const repositoryPiecesAux: PiecesRepository = {}; - const foragePieces: PieceForageSchema = {}; - if (!active) { - return; - } - if (!repositories?.data?.length) { - localStorage.setItem("pieces", foragePieces); - setRepositoryPieces(repositoryPiecesAux); - } else { - for (const repo of repositories.data) { - await fetchRepoById({ id: repo.id }) - .then((pieces: any) => { - repositoryPiecesAux[repo.id] = []; - for (const op of pieces) { - repositoryPiecesAux[repo.id].push(op); - foragePieces[op.id] = op; - } - localStorage.setItem("pieces", foragePieces); - }) - .catch((e) => { - console.log(e); - }); - } - setRepositoryPieces(repositoryPiecesAux); - } - } - }, [repositories, fetchRepoById]); + const queryClient = useQueryClient(); - const { data: defaultRepositories } = useAuthenticatedGetPieceRepositories({ + const { data: defaultRepositories } = useRepositories({ source: "default", }); - const fetchForagePieceById = useCallback((id: number) => { - const pieces = localStorage.getItem("pieces"); - if (pieces !== null) { - return pieces[id]; - } - }, []); + const { data: repositories, isLoading: repositoriesLoading } = + useRepositories({ + workspaceId: workspace?.id, + source: "github", + }); - const postRepository = useAuthenticatedPostPiecesRepository({ - workspace: workspace?.id ?? "", + const { data: pieces } = usePieces({ + repositoryIds: repositories?.data.map(({ id }) => id) ?? [], }); - const handleAddRepository = useCallback( - async (payload: Omit) => - await postRepository({ - ...payload, - workspace_id: workspace?.id ?? "", - }).then(async (data) => { + const { data: _defaultPieces } = usePieces({ + repositoryIds: defaultRepositories?.data.map(({ id }) => id) ?? [], + }); + + const { mutateAsync: handleFetchRepoReleases } = useRepositoriesReleases({ + workspaceId: workspace?.id, + }); + + const { mutateAsync: handleAddRepository } = useAddRepository( + { + workspaceId: workspace?.id, + }, + { + onSuccess: async () => { toast.success(`Repository added successfully!`); - handleRefreshWorkspaces(); - await handleRefreshRepositories(); - return data; - }), - [postRepository, handleRefreshWorkspaces, workspace?.id], + await queryClient.invalidateQueries({ + queryKey: ["REPOSITORIES", workspace?.id], + }); + }, + }, ); - const handleFetchRepoReleases = - useAuthenticatedGetPieceRepositoriesReleases(); + const { mutateAsync: handleDeleteRepository } = useDeleteRepository({ + onSuccess: async () => { + await queryClient.invalidateQueries({ queryKey: ["REPOSITORIES"] }); + }, + }); + + const repositoryPieces = useMemo(() => { + const repositoryPiecesAux: PiecesRepository = {}; + const foragePieces: PieceForageSchema = {}; + + if (!pieces?.length) { + localStorage.setItem("pieces", foragePieces); + return repositoryPiecesAux; + } else { + for (const piece of pieces) { + if (repositoryPiecesAux[piece.repository_id]?.length) { + repositoryPiecesAux[piece.repository_id].push(piece); + } else { + repositoryPiecesAux[piece.repository_id] = []; + repositoryPiecesAux[piece.repository_id].push(piece); + } + foragePieces[piece.id] = piece; + } - const handleDeleteRepository = useAuthenticatedDeleteRepository(); + localStorage.setItem("pieces", foragePieces); + return repositoryPiecesAux; + } + }, [pieces]); - useEffect(() => { - if (repositoriesError) { - toast.error("Error loading repositories, try again later"); + const fetchForagePieceById = useCallback((id: number) => { + const pieces = localStorage.getItem("pieces"); + if (pieces !== null) { + return pieces[id]; } - }, [repositoriesError]); + }, []); const value: IPiecesContext = { repositories: repositories?.data ?? [], @@ -162,13 +139,11 @@ const PiecesProvider: React.FC<{ children: React.ReactNode }> = ({ selectedRepositoryId, setSelectedRepositoryId, - handleRefreshRepositories, handleAddRepository, handleFetchRepoReleases, handleDeleteRepository, fetchForagePieceById, - fetchRepoById, }; return ( diff --git a/frontend/src/context/workspaces/types/workspaces.ts b/frontend/src/context/workspaces/types/workspaces.ts index 1b792a4e..f7e5c482 100644 --- a/frontend/src/context/workspaces/types/workspaces.ts +++ b/frontend/src/context/workspaces/types/workspaces.ts @@ -1,3 +1,5 @@ +import { type Roles } from "@utils/roles"; + export enum repositorySource { github = "github", } @@ -9,35 +11,20 @@ export enum workspaceStatus { REJECTED = "rejected", } -interface IPaginationMetadata { - page: number; - records: number; - total: number; - last_page: number; -} - -export interface IWorkspaceSummary { +export interface WorkspaceSummary { id: string; workspace_name: string; - user_permission: string; + user_permission: Roles; status: workspaceStatus; github_access_token_filled: boolean; } -export interface IWorkspaceDetails { +export interface WorkspaceDetails { id: string; workspace_name: string; github_access_token_filled: string; - // users: { user_id: string, permission: string }[] - // Pieces_repositories: { - // repository_id: string - // repository_name: string - // repository_source: ERepositorySource | string - // }[] } -export type IGetWorkspacesResponseInterface = IWorkspaceSummary[]; -export type IGetWorkspaceIdResponseInterface = IWorkspaceSummary; export interface IGetWorkspaceUsersResponse { data: [ { @@ -47,14 +34,9 @@ export interface IGetWorkspaceUsersResponse { status: workspaceStatus; }, ]; - metadata: IPaginationMetadata; + metadata: PaginationMetadata; } -/** - * @todo type properly - */ -export type IPostWorkspaceRepositoryResponseInterface = Record; - export interface IPostWorkspaceRepositoryPayload { workspace_id: string; source: repositorySource | string; diff --git a/frontend/src/context/workspaces/workspaces.tsx b/frontend/src/context/workspaces/workspaces.tsx index d449050b..6de421cc 100644 --- a/frontend/src/context/workspaces/workspaces.tsx +++ b/frontend/src/context/workspaces/workspaces.tsx @@ -1,30 +1,31 @@ +import { + useGetWorkspaces, + useCreateWorkspace, + useDeleteWorkspace, + useAcceptWorkspaceInvite, + useRejectWorkspaceInvite, + useInviteWorkspace, + useRemoveUserFomWorkspace, + useWorkspaceUsers, +} from "@features/workspaces"; +import { useQueryClient } from "@tanstack/react-query"; import { type FC, useCallback, useMemo, useState } from "react"; import { toast } from "react-toastify"; import { createCustomContext } from "utils"; -import { - useAuthenticatedGetWorkspaces, - useAuthenticatedPostWorkspaces, - useAuthenticatedDeleteWorkspaces, - useAuthenticatedAcceptWorkspaceInvite, - useAuthenticatedRejectWorkspaceInvite, - useAuthenticatedWorkspaceInvite, - useAuthenticatedRemoveUserWorkspace, - useAuthenticatedGetWorkspaceUsers, -} from "./api"; -import { type IWorkspaceSummary } from "./types/workspaces"; +import { type WorkspaceSummary } from "./types/workspaces"; interface IWorkspacesContext { - workspaces: IWorkspaceSummary[]; + workspaces: WorkspaceSummary[]; workspacesError: boolean; workspacesLoading: boolean; handleRefreshWorkspaces: () => void; - workspace: IWorkspaceSummary | null; + workspace: WorkspaceSummary | null; handleChangeWorkspace: (id: string) => void; handleCreateWorkspace: (name: string) => Promise; handleDeleteWorkspace: (id: string) => void; - handleUpdateWorkspace: (workspace: IWorkspaceSummary) => void; + handleUpdateWorkspace: (workspace: WorkspaceSummary) => void; handleAcceptWorkspaceInvite: (id: string) => void; handleRejectWorkspaceInvite: (id: string) => void; handleInviteUserWorkspace: ( @@ -34,7 +35,6 @@ interface IWorkspacesContext { ) => void; handleRemoveUserWorkspace: (workspaceId: string, userId: string) => void; workspaceUsers: any; - workspaceUsersRefresh: () => void; workspaceUsersTablePageSize: number; workspaceUsersTablePage: number; setWorkspaceUsersTablePageSize: (pageSize: number) => void; @@ -51,10 +51,10 @@ interface IWorkspacesProviderProps { export const WorkspacesProvider: FC = ({ children, }) => { - const [workspace, setWorkspace] = useState( + const [workspace, setWorkspace] = useState( localStorage.getItem("workspace") ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - (JSON.parse(localStorage.getItem("workspace")!) as IWorkspaceSummary) + (JSON.parse(localStorage.getItem("workspace")!) as WorkspaceSummary) : null, ); @@ -63,39 +63,54 @@ export const WorkspacesProvider: FC = ({ const [workspaceUsersTablePage, setWorkspaceUsersTablePage] = useState(0); + const queryClient = useQueryClient(); + // Requests hooks const { data, error: workspacesError, - isValidating: workspacesLoading, - mutate: workspacesRefresh, - } = useAuthenticatedGetWorkspaces(); + isLoading: workspacesLoading, + refetch: workspacesRefresh, + } = useGetWorkspaces(); - const { data: workspaceUsers, mutate: workspaceUsersRefresh } = - useAuthenticatedGetWorkspaceUsers( - workspace - ? { - workspaceId: workspace.id, - page: workspaceUsersTablePage, - pageSize: workspaceUsersTablePageSize, - } - : { - workspaceId: "", - page: workspaceUsersTablePage, - pageSize: workspaceUsersTablePageSize, - }, - ); + const { data: workspaceUsers } = useWorkspaceUsers({ + workspaceId: workspace?.id, + page: workspaceUsersTablePage, + pageSize: workspaceUsersTablePageSize, + }); - const postWorkspace = useAuthenticatedPostWorkspaces(); - const deleteWorkspace = useAuthenticatedDeleteWorkspaces(); + const { mutateAsync: postWorkspace } = useCreateWorkspace(); + const { mutateAsync: deleteWorkspace } = useDeleteWorkspace(); - const acceptWorkspaceInvite = useAuthenticatedAcceptWorkspaceInvite(); - const rejectWorkspaceInvite = useAuthenticatedRejectWorkspaceInvite(); - const inviteWorkspace = useAuthenticatedWorkspaceInvite(); - const removeUserWorkspace = useAuthenticatedRemoveUserWorkspace(); + const { mutateAsync: acceptWorkspaceInvite } = useAcceptWorkspaceInvite(); + const { mutateAsync: rejectWorkspaceInvite } = useRejectWorkspaceInvite(); + const { mutateAsync: inviteWorkspace } = useInviteWorkspace( + { + workspaceId: workspace?.id, + }, + { + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: ["USERS"], + }); + }, + }, + ); + const { mutateAsync: removeUserWorkspace } = useRemoveUserFomWorkspace( + { + workspaceId: workspace?.id, + }, + { + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: ["USERS"], + }); + }, + }, + ); // Memoized data - const workspaces: IWorkspaceSummary[] = useMemo(() => data ?? [], [data]); + const workspaces: WorkspaceSummary[] = useMemo(() => data ?? [], [data]); // Handlers const handleRemoveUserWorkspace = useCallback( @@ -105,7 +120,7 @@ export const WorkspacesProvider: FC = ({ "Workspace and user must be defined to remove user from workspace.", ); } - removeUserWorkspace({ workspaceId, userId }) + removeUserWorkspace({ userId }) .then(() => { toast.success(`User removed successfully from workspace.`); const storageWorkspace = JSON.parse( @@ -118,7 +133,7 @@ export const WorkspacesProvider: FC = ({ void workspacesRefresh(); }) .catch((error) => { - console.log("Removing user error:", error.response.data.detail); + console.error("Removing user error:", error.response.data.detail); }); }, [removeUserWorkspace, workspacesRefresh], @@ -130,19 +145,17 @@ export const WorkspacesProvider: FC = ({ return false; } inviteWorkspace({ - workspaceId: id, userEmail, permission, }) .then(() => { toast.success(`User invited successfully`); - void workspaceUsersRefresh(); }) .catch((error) => { - console.log("Inviting user error:", error.response.data.detail); + console.error("Inviting user error:", error.response.data.detail); }); }, - [inviteWorkspace, workspaceUsersRefresh()], + [inviteWorkspace], ); const handleAcceptWorkspaceInvite = useCallback( @@ -153,9 +166,7 @@ export const WorkspacesProvider: FC = ({ void workspacesRefresh(); }) .catch((error) => { - // todo custom msg - console.log("Accepting workspace invitation error:", error); - toast.error("Error accepting workspace invitation, try again later"); + console.error("Accepting workspace invitation error:", error); }); }, [acceptWorkspaceInvite, workspacesRefresh], @@ -169,9 +180,7 @@ export const WorkspacesProvider: FC = ({ void workspacesRefresh(); }) .catch((error) => { - // todo custom msg - console.log("Rejecting workspace invitation error:", error); - toast.error("Error rejecting workspace invitation, try again later"); + console.error("Rejecting workspace invitation error:", error); }); }, [rejectWorkspaceInvite, workspacesRefresh], @@ -179,10 +188,9 @@ export const WorkspacesProvider: FC = ({ const handleCreateWorkspace = useCallback( async (name: string) => - await postWorkspace({ name }) + postWorkspace({ name }) .then((data) => { toast.success(`Workspace ${name} created successfully`); - void workspacesRefresh(); return data; }) .catch(() => { @@ -190,7 +198,7 @@ export const WorkspacesProvider: FC = ({ }), [postWorkspace, workspacesRefresh], ); - const handleUpdateWorkspace = useCallback((workspace: IWorkspaceSummary) => { + const handleUpdateWorkspace = useCallback((workspace: WorkspaceSummary) => { setWorkspace(workspace); localStorage.setItem("workspace", JSON.stringify(workspace)); }, []); @@ -208,7 +216,7 @@ export const WorkspacesProvider: FC = ({ const handleDeleteWorkspace = useCallback( (id: string) => { - deleteWorkspace({ id }) + deleteWorkspace({ workspaceId: id }) .then(() => { const storageWorkspace = JSON.parse( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -221,12 +229,7 @@ export const WorkspacesProvider: FC = ({ void workspacesRefresh(); }) .catch((error) => { - console.log("Deleting workspace error:", error); - if (error.response.status === 403) { - toast.error("You don't have permission to delete this workspace."); - return; - } - toast.error("Error deleting workspace, try again later"); + console.error("Deleting workspace error:", error); }); }, [deleteWorkspace, workspacesRefresh], @@ -238,7 +241,7 @@ export const WorkspacesProvider: FC = ({ workspaces, workspacesError: !!workspacesError, workspacesLoading, - handleRefreshWorkspaces: async () => await workspacesRefresh(), + handleRefreshWorkspaces: async () => workspacesRefresh(), workspace, handleChangeWorkspace, handleCreateWorkspace, @@ -249,7 +252,6 @@ export const WorkspacesProvider: FC = ({ handleInviteUserWorkspace, handleRemoveUserWorkspace, workspaceUsers, - workspaceUsersRefresh, workspaceUsersTablePageSize, workspaceUsersTablePage, setWorkspaceUsersTablePageSize, diff --git a/frontend/src/features/auth/api/index.ts b/frontend/src/features/auth/api/index.ts new file mode 100644 index 00000000..9eb2fc4b --- /dev/null +++ b/frontend/src/features/auth/api/index.ts @@ -0,0 +1,2 @@ +export * from "./useAuthLogin"; +export * from "./useAuthRegister"; diff --git a/frontend/src/features/auth/api/useAuthLogin.ts b/frontend/src/features/auth/api/useAuthLogin.ts new file mode 100644 index 00000000..e2220807 --- /dev/null +++ b/frontend/src/features/auth/api/useAuthLogin.ts @@ -0,0 +1,32 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface LoginParams { + email: string; + password: string; +} + +interface LoginResponse { + user_id: string; + group_ids: number[]; + access_token: string; + token_expires_in: number; +} + +export const useAuthLogin = ( + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async ({ email, password }) => + await postAuthLogin({ email, password }), + ...config, + }); +}; + +const postAuthLogin = async ({ + email, + password, +}: LoginParams): Promise => { + return await dominoApiClient.post("/auth/login", { email, password }); +}; diff --git a/frontend/src/features/auth/api/useAuthRegister.ts b/frontend/src/features/auth/api/useAuthRegister.ts new file mode 100644 index 00000000..b1c151a1 --- /dev/null +++ b/frontend/src/features/auth/api/useAuthRegister.ts @@ -0,0 +1,31 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface RegisterParams { + email: string; + password: string; +} + +interface RegisterResponse { + user_id: string; + email: string; + token_expires_in: number; + groups: Array<{ group_id: number; group_name: string }>; +} + +export const useAuthRegister = ( + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async (params) => await postAuthRegister(params), + ...config, + }); +}; + +const postAuthRegister = async ({ + email, + password, +}: RegisterParams): Promise => { + return await dominoApiClient.post("/auth/register", { email, password }); +}; diff --git a/frontend/src/features/auth/index.ts b/frontend/src/features/auth/index.ts new file mode 100644 index 00000000..793a09b8 --- /dev/null +++ b/frontend/src/features/auth/index.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./routes"; diff --git a/frontend/src/features/auth/pages/signIn/signInPage.tsx b/frontend/src/features/auth/pages/signIn/signInPage.tsx index feabcbb3..196b38f6 100644 --- a/frontend/src/features/auth/pages/signIn/signInPage.tsx +++ b/frontend/src/features/auth/pages/signIn/signInPage.tsx @@ -59,7 +59,7 @@ export const SignInPage: FC = () => { }} > logo diff --git a/frontend/src/features/auth/pages/signUp/signUpPage.tsx b/frontend/src/features/auth/pages/signUp/signUpPage.tsx index bcc91895..4ef221d8 100644 --- a/frontend/src/features/auth/pages/signUp/signUpPage.tsx +++ b/frontend/src/features/auth/pages/signUp/signUpPage.tsx @@ -15,11 +15,6 @@ import { Link } from "react-router-dom"; import { yupResolver } from "utils"; import * as yup from "yup"; -/** - * Sign up component - * @TODO: differentiate more from the login page? - */ - interface ISignUp { email: string; password: string; @@ -67,7 +62,7 @@ export const SignUpPage: FC = () => { }} > logo diff --git a/frontend/src/features/auth/routes/index.tsx b/frontend/src/features/auth/routes/index.tsx new file mode 100644 index 00000000..90fb0386 --- /dev/null +++ b/frontend/src/features/auth/routes/index.tsx @@ -0,0 +1,27 @@ +import { NotFoundRoute } from "@components/Routes/NotFoundRoute"; +import { PublicRoute } from "@components/Routes/PublicRoute"; +import React from "react"; +import { Navigate, Route, Routes } from "react-router-dom"; + +import SignInPage from "../pages/signIn/signInPage"; +import SignUpPage from "../pages/signUp/signUpPage"; + +export const AuthRoutes: React.FC = () => { + return ( + + }> + } /> + } /> + Recover password} /> + } />, + + } + /> + , + + + ); +}; diff --git a/frontend/src/features/myWorkflows/api/index.ts b/frontend/src/features/myWorkflows/api/index.ts index 523a1a7c..600608dc 100644 --- a/frontend/src/features/myWorkflows/api/index.ts +++ b/frontend/src/features/myWorkflows/api/index.ts @@ -1,4 +1,2 @@ export * from "./runs"; export * from "./workflow"; -export * from "./piece"; -export * from "./repository"; diff --git a/frontend/src/features/myWorkflows/api/piece/getPieceRepositories.request.ts b/frontend/src/features/myWorkflows/api/piece/getPieceRepositories.request.ts deleted file mode 100644 index bfb14906..00000000 --- a/frontend/src/features/myWorkflows/api/piece/getPieceRepositories.request.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -import { type IGetPiecesRepositoriesResponseInterface } from "./piece.interface"; - -interface IGetPieceRepositoryFilters { - page?: number; - page_size?: number; - name__like?: string; - path__like?: string; - version?: string; - source?: "github" | "default"; -} - -const getPiecesRepositoriesUrl = ( - filters: IGetPieceRepositoryFilters, - workspace?: string, -) => { - if (!workspace) { - return null; - } - const query = new URLSearchParams(); - query.set("workspace_id", workspace); - for (const [key, value] of Object.entries(filters)) { - query.set(key, value); - } - return `/pieces-repositories?${query.toString()}`; -}; - -/** - * Get Piece using GET /pieces-repositories - * @returns Piece - */ -const getPiecesRepositories: ( - filters: IGetPieceRepositoryFilters, - workspace?: string, -) => Promise< - AxiosResponse | undefined -> = async (filters, workspace) => { - // - if (workspace) { - return await dominoApiClient.get( - getPiecesRepositoriesUrl(filters, workspace) as string, - ); - } -}; - -/** - * Get pieces repositories for current workspace - * @returns pieces repositories as swr response - */ -export const useAuthenticatedGetPieceRepositories = ( - filters: IGetPieceRepositoryFilters, -) => { - const { workspace } = useWorkspaces(); - - const fetcher = async (filters: IGetPieceRepositoryFilters) => - await getPiecesRepositories(filters, workspace?.id).then( - (data) => data?.data, - ); - - return useSWR( - getPiecesRepositoriesUrl(filters, workspace?.id), - async () => await fetcher(filters), - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }, - ); -}; diff --git a/frontend/src/features/myWorkflows/api/piece/getPieceRepositoryPieces.ts b/frontend/src/features/myWorkflows/api/piece/getPieceRepositoryPieces.ts deleted file mode 100644 index b5fbefca..00000000 --- a/frontend/src/features/myWorkflows/api/piece/getPieceRepositoryPieces.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useCallback } from "react"; -import { dominoApiClient } from "services/clients/domino.client"; - -import { type IGetRepoPiecesResponseInterface } from "./piece.interface"; - -interface IGetRepoPiecesParams { - id: string; -} - -/** - * Get pieces for selected repository using GET /pieces-repositories/{id}/pieces - * @param token auth token (string) - * @param id repo id - * @returns pieces - */ -const getRepoIdPieces: (args: { - params: IGetRepoPiecesParams; -}) => Promise> = async ({ - params, -}) => { - return await dominoApiClient.get(`pieces-repositories/${params.id}/pieces`); -}; - -/** - * Get pieces by repo id authenticated fetcher function - * @param params `{ id: string }` - * @returns pieces from repo - */ -export const useFetchAuthenticatedGetRepoIdPieces = () => { - const fetcher = useCallback(async (params: IGetRepoPiecesParams) => { - return await getRepoIdPieces({ params }).then((data) => data.data); - }, []); - return fetcher; -}; diff --git a/frontend/src/features/myWorkflows/api/piece/getPiecesRepositoriesReleases.request.ts b/frontend/src/features/myWorkflows/api/piece/getPiecesRepositoriesReleases.request.ts deleted file mode 100644 index f4cf28c8..00000000 --- a/frontend/src/features/myWorkflows/api/piece/getPiecesRepositoriesReleases.request.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; - -import { - type IGetPiecesRepositoriesReleasesParams, - type IGetPiecesRepositoriesReleasesResponseInterface, -} from "./piece.interface"; - -/** - * Get Piece repository releases using GET /pieces-repositories/releases - * @param token auth token (string) - * @returns Piece repository - */ -const getPiecesRepositoriesReleases: ( - params: IGetPiecesRepositoriesReleasesParams, -) => Promise< - AxiosResponse | undefined -> = async ({ source, path, workspaceId }) => { - if (!workspaceId) { - return; - } - const search = new URLSearchParams(); - search.set("source", source); - search.set("path", path); - search.set("workspace_id", workspaceId); - - return await dominoApiClient.get( - `/pieces-repositories/releases?${search.toString()}`, - ); -}; - -/** - * Get releases for a given Piece repository - * @returns pieces repositories releases - */ -export const useAuthenticatedGetPieceRepositoriesReleases = () => { - const { workspace } = useWorkspaces(); - - return async (params: IGetPiecesRepositoriesReleasesParams) => - await getPiecesRepositoriesReleases({ - ...params, - workspaceId: workspace?.id, - }).then((data) => { - return data?.data; - }); -}; diff --git a/frontend/src/features/myWorkflows/api/piece/index.ts b/frontend/src/features/myWorkflows/api/piece/index.ts deleted file mode 100644 index 867aec15..00000000 --- a/frontend/src/features/myWorkflows/api/piece/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./getPieceRepositories.request"; -export * from "./getPieceRepositoryPieces"; -export * from "./getPiecesRepositoriesReleases.request"; -export * from "./piece.interface"; diff --git a/frontend/src/features/myWorkflows/api/piece/piece.interface.ts b/frontend/src/features/myWorkflows/api/piece/piece.interface.ts deleted file mode 100644 index 1f3ff587..00000000 --- a/frontend/src/features/myWorkflows/api/piece/piece.interface.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { type repositorySource } from "context/workspaces/types"; - -interface IPaginationMetadata { - page: number; - records: number; - total: number; - last_page: number; -} - -/** - * Get Piece Repositories response interface - */ -export interface IGetPiecesRepositoriesResponseInterface { - data: Repository[]; - metadata: IPaginationMetadata; -} - -/** - * Get Piece Repositories id Pieces - */ -export type IGetRepoPiecesResponseInterface = Piece[]; - -/** - * Piece repository metadata - */ -export interface IPieceRepositoryMetadata { - version: string; - last_modified: string; -} - -/** - * Get Pieces Repositories Releases response interface - */ -export type IGetPiecesRepositoriesReleasesResponseInterface = - IPieceRepositoryMetadata[]; - -/** - * Get Pieces Repositories Releases request params - */ -export interface IGetPiecesRepositoriesReleasesParams { - source: repositorySource; - path: string; - workspaceId?: string; -} diff --git a/frontend/src/features/myWorkflows/api/repository/deletePieceRepository.request.ts b/frontend/src/features/myWorkflows/api/repository/deletePieceRepository.request.ts deleted file mode 100644 index 1c33f61e..00000000 --- a/frontend/src/features/myWorkflows/api/repository/deletePieceRepository.request.ts +++ /dev/null @@ -1,29 +0,0 @@ -// TODO move to /runs -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; - -const deleteRepositoryUrl = (id: string) => `/pieces-repositories/${id}`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const deleteRepository: (id: string) => Promise = async (id) => { - return await dominoApiClient.delete(deleteRepositoryUrl(id)); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedDeleteRepository = () => { - const { workspace } = useWorkspaces(); - - if (!workspace) return async (_id: string) => {}; - - const fetcher = async (id: string) => - await deleteRepository(id).then((data) => data); - - return fetcher; -}; diff --git a/frontend/src/features/myWorkflows/api/repository/getPieceRepositorySecrets.request.ts b/frontend/src/features/myWorkflows/api/repository/getPieceRepositorySecrets.request.ts deleted file mode 100644 index e85759a5..00000000 --- a/frontend/src/features/myWorkflows/api/repository/getPieceRepositorySecrets.request.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -import { type IPieceRepositorySecretsData } from "./pieceRepository.interface"; - -interface IGetRepositorySecretsParams { - repositoryId: string; -} - -const getRepositorySecretsUrl = (repositoryId: string) => - `/pieces-repositories/${repositoryId}/secrets`; - -/** - * Get workflows using GET /workflows - * @returns workflow - */ -const getRepositorySecrets: ( - repositoryId: string, -) => Promise> = async ( - repositoryId, -) => { - return await dominoApiClient.get(getRepositorySecretsUrl(repositoryId)); -}; - -export const useAuthenticatedGetWorkflowRunTasksFetcher = () => { - const { workspace } = useWorkspaces(); - - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - return async (params: IGetRepositorySecretsParams) => - await getRepositorySecrets(params.repositoryId).then((data) => data.data); -}; - -/** - * Get workflow runs - * @returns runs as swr response - */ -export const useAuthenticatedGetRepositorySecrets = ( - params: IGetRepositorySecretsParams, -) => { - const { workspace } = useWorkspaces(); - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - const fetcher = useAuthenticatedGetWorkflowRunTasksFetcher(); - - return useSWR( - params.repositoryId ? getRepositorySecretsUrl(params.repositoryId) : null, - async () => await fetcher(params), - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }, - ); -}; diff --git a/frontend/src/features/myWorkflows/api/repository/index.ts b/frontend/src/features/myWorkflows/api/repository/index.ts deleted file mode 100644 index 91a74f87..00000000 --- a/frontend/src/features/myWorkflows/api/repository/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./getPieceRepositorySecrets.request"; -export * from "./patchPieceRepositorySecret.request"; -export * from "./deletePieceRepository.request"; diff --git a/frontend/src/features/myWorkflows/api/repository/patchPieceRepositorySecret.request.ts b/frontend/src/features/myWorkflows/api/repository/patchPieceRepositorySecret.request.ts deleted file mode 100644 index 6b774972..00000000 --- a/frontend/src/features/myWorkflows/api/repository/patchPieceRepositorySecret.request.ts +++ /dev/null @@ -1,43 +0,0 @@ -// TODO move to /runs -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface PatchRepositorySecretParams { - repositoryId: string; - secretId: string; - payload: { - value: string | null; - }; -} - -const patchRepositorySecretUrl = (repositoryId: string, secretId: string) => - `/pieces-repositories/${repositoryId}/secrets/${secretId}`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const patchRepositorySecret: ( - params: PatchRepositorySecretParams, -) => Promise = async (params) => { - return await dominoApiClient.patch( - patchRepositorySecretUrl(params.repositoryId, params.secretId), - params.payload, - ); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedPatchRepositorySecret = () => { - const { workspace } = useWorkspaces(); - - if (!workspace) return async (_params: PatchRepositorySecretParams) => {}; - - const fetcher = async (params: PatchRepositorySecretParams) => - await patchRepositorySecret(params).then((data) => data); - - return fetcher; -}; diff --git a/frontend/src/features/myWorkflows/api/repository/pieceRepository.interface.ts b/frontend/src/features/myWorkflows/api/repository/pieceRepository.interface.ts deleted file mode 100644 index 224fdef7..00000000 --- a/frontend/src/features/myWorkflows/api/repository/pieceRepository.interface.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface IPieceRepositorySecretsData { - id: number; - name: string; - is_filled: boolean; -} diff --git a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunReport.ts b/frontend/src/features/myWorkflows/api/runs/getWorkflowRunReport.ts deleted file mode 100644 index 465446c1..00000000 --- a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunReport.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { type taskState } from "features/myWorkflows/types"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -export interface IGetWorkflowRunResultReportParams { - workflowId: string; - runId: string; -} - -export interface IGetWorkflowRunResultReportResponse { - base64_content: string; - file_type: string; - piece_name: string; - dag_id: string; - duration: number; - start_date: string; - end_date: string; - execution_date: string; - task_id: string; - state: taskState; -} - -const getWorkflowRunResultReportUrl = ({ - workspace, - workflowId, - runId, -}: Partial) => { - if (workspace && workflowId && runId) { - return `/workspaces/${workspace}/workflows/${workflowId}/runs/${runId}/tasks/report`; - } else { - return null; - } -}; - -/** - * Get workflows using GET /workflows - * @returns workflow - */ -const getWorkflowRunResultReport: ({ - workspace, - workflowId, - runId, -}: Partial< - IGetWorkflowRunResultReportParams & { workspace: string } ->) => Promise< - | AxiosResponse<{ - data: IGetWorkflowRunResultReportResponse[]; - }> - | undefined -> = async ({ workspace, workflowId, runId }) => { - if (workspace && workflowId && runId) { - const url = getWorkflowRunResultReportUrl({ - workspace, - workflowId, - runId, - }); - if (url) return await dominoApiClient.get(url); - } -}; - -/** - * Get workflow runs - * @returns runs as swr response - */ -export const useAuthenticatedGetWorkflowRunResultReport = ( - params: Partial, -) => { - const { workspace } = useWorkspaces(); - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - const url = getWorkflowRunResultReportUrl({ - workspace: workspace.id, - ...params, - }); - - return useSWR( - url, - async () => - await getWorkflowRunResultReport({ - workspace: workspace.id, - ...params, - }).then((data) => data?.data), - ); -}; diff --git a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTaskLogs.ts b/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTaskLogs.ts deleted file mode 100644 index ee8601b0..00000000 --- a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTaskLogs.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -export interface IGetWorkflowRunTaskLogsParams { - workflowId: string; - runId: string; - taskId: string; - taskTryNumber: string; -} - -const getWorkflowRunTaskLogsUrl = ( - workspace: string, - workflowId: string, - runId: string, - taskId: string, - taskTryNumber: string, -) => { - if (workspace && workflowId && runId && taskId && taskTryNumber) { - return `/workspaces/${workspace}/workflows/${workflowId}/runs/${runId}/tasks/${taskId}/${taskTryNumber}/logs`; - } -}; - -/** - * Get workflows using GET /workflows - * @returns workflow - */ -const getWorkflowRunTaskLogs: ( - workspace: string, - workflowId: string, - runId: string, - taskId: string, - taskTryNumber: string, -) => Promise | undefined> = async ( - workspace, - workflowId, - runId, - taskId, - taskTryNumber, -) => { - const url = getWorkflowRunTaskLogsUrl( - workspace, - workflowId, - runId, - taskId, - taskTryNumber, - ); - if (url) return await dominoApiClient.get(url); -}; - -/** - * Get workflow runs - * @returns runs as swr response - */ -export const useAuthenticatedGetWorkflowRunTaskLogs = ( - params: IGetWorkflowRunTaskLogsParams, -) => { - const { workspace } = useWorkspaces(); - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - return useSWR( - getWorkflowRunTaskLogsUrl( - workspace.id, - params.workflowId, - params.runId, - params.taskId, - params.taskTryNumber, - ) ?? null, - async () => - await getWorkflowRunTaskLogs( - workspace.id, - params.workflowId, - params.runId, - params.taskId, - params.taskTryNumber, - ).then((data) => data?.data), - ); -}; diff --git a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTaskResult.ts b/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTaskResult.ts deleted file mode 100644 index 21c71550..00000000 --- a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTaskResult.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -export interface IGetWorkflowRunTaskResultParams { - workflowId: string; - runId: string; - taskId: string; - taskTryNumber: string; -} - -const getWorkflowRunTaskResultUrl = ({ - workspace, - workflowId, - runId, - taskId, - taskTryNumber, -}: Partial) => { - if (workspace && workflowId && runId && taskId && taskTryNumber) { - return `/workspaces/${workspace}/workflows/${workflowId}/runs/${runId}/tasks/${taskId}/${taskTryNumber}/result`; - } else { - return null; - } -}; - -/** - * Get workflows using GET /workflows - * @returns workflow - */ -const getWorkflowRunTaskResult: ({ - workspace, - workflowId, - runId, - taskId, - taskTryNumber, -}: Partial) => Promise< - AxiosResponse<{ base64_content: string; file_type: string }> | undefined -> = async ({ workspace, workflowId, runId, taskId, taskTryNumber }) => { - if (workspace && workflowId && runId && taskId && taskTryNumber) { - const url = getWorkflowRunTaskResultUrl({ - workspace, - workflowId, - runId, - taskId, - taskTryNumber, - }); - if (url) return await dominoApiClient.get(url); - } -}; - -/** - * Get workflow runs - * @returns runs as swr response - */ -export const useAuthenticatedGetWorkflowRunTaskResult = ( - params: Partial, -) => { - const { workspace } = useWorkspaces(); - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - const url = getWorkflowRunTaskResultUrl({ - workspace: workspace.id, - ...params, - }); - - return useSWR( - url, - async () => - await getWorkflowRunTaskResult({ - workspace: workspace.id, - ...params, - }).then((data) => data?.data), - ); -}; diff --git a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTasks.ts b/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTasks.ts deleted file mode 100644 index 7ca82299..00000000 --- a/frontend/src/features/myWorkflows/api/runs/getWorkflowRunTasks.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { type IGetWorkflowRunTasksResponseInterface } from "features/myWorkflows/types/runs"; -import { dominoApiClient } from "services/clients/domino.client"; - -export interface IGetWorkflowRunTasksParams { - workflowId: string; - runId: string; - page: number; - pageSize: number; -} - -const getWorkflowRunTasksUrl = ( - workspace: string, - workflowId: string, - runId: string, - page: number, - pageSize: number, -) => - `/workspaces/${workspace}/workflows/${workflowId}/runs/${runId}/tasks?page=${page}&page_size=${pageSize}`; - -/** - * Get workflows using GET /workflows - * @returns workflow - */ -const getWorkflowRunTasks: ( - workspace: string, - workflowId: string, - runId: string, - page: number, - pageSize: number, -) => Promise> = async ( - workspace, - workflowId, - runId, - page, - pageSize, -) => { - return await dominoApiClient.get( - getWorkflowRunTasksUrl(workspace, workflowId, runId, page, pageSize), - ); -}; - -/** - * Get workflow runs - * @returns runs as swr response - */ -export const useAuthenticatedGetWorkflowRunTasks = () => { - const { workspace } = useWorkspaces(); - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - return async (params: IGetWorkflowRunTasksParams) => - await getWorkflowRunTasks( - workspace.id, - params.workflowId, - params.runId, - params.page, - params.pageSize, - ).then((data) => data.data); -}; diff --git a/frontend/src/features/myWorkflows/api/runs/getWorkflowRuns.ts b/frontend/src/features/myWorkflows/api/runs/getWorkflowRuns.ts deleted file mode 100644 index ce71d34e..00000000 --- a/frontend/src/features/myWorkflows/api/runs/getWorkflowRuns.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { type IGetWorkflowRunsResponseInterface } from "features/myWorkflows/types/runs"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -interface IGetWorkflowRunParams { - workflowId: string; - page: number; - pageSize: number; -} - -const getWorkflowRunsUrl = ( - workspace: string, - workflowId: string, - page: number, - pageSize: number, -) => - `/workspaces/${workspace}/workflows/${workflowId}/runs?page=${page}&page_size=${pageSize}`; - -/** - * Get workflows using GET /workflows - * @returns workflow - */ -const getWorkflowRuns: ( - workspace: string, - workflowId: string, - page: number, - pageSize: number, -) => Promise> = async ( - workspace, - workflowId, - page, - pageSize, -) => { - return await dominoApiClient.get( - getWorkflowRunsUrl(workspace, workflowId, page, pageSize), - ); -}; - -export const useAuthenticatedGetWorkflowRunFetcher = () => { - const { workspace } = useWorkspaces(); - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - return async (params: IGetWorkflowRunParams) => - await getWorkflowRuns( - workspace.id, - params.workflowId, - params.page, - params.pageSize, - ).then((data) => data.data); -}; - -/** - * Get workflow runs - * @returns runs as swr response - */ -export const useAuthenticatedGetWorkflowRuns = ( - params: IGetWorkflowRunParams, -) => { - const { workspace } = useWorkspaces(); - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - const fetcher = useAuthenticatedGetWorkflowRunFetcher(); - - return useSWR( - params.workflowId - ? getWorkflowRunsUrl( - workspace.id, - params.workflowId, - params.page, - params.pageSize, - ) - : null, - async () => await fetcher(params), - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }, - ); -}; diff --git a/frontend/src/features/myWorkflows/api/runs/index.ts b/frontend/src/features/myWorkflows/api/runs/index.ts index 5e427087..238502f3 100644 --- a/frontend/src/features/myWorkflows/api/runs/index.ts +++ b/frontend/src/features/myWorkflows/api/runs/index.ts @@ -1,5 +1,6 @@ -export * from "./getWorkflowRuns"; -export * from "./getWorkflowRunTasks"; -export * from "./getWorkflowRunTaskLogs"; -export * from "./getWorkflowRunTaskResult"; -export * from "./getWorkflowRunReport"; +export * from "./useRunReport"; +export * from "./useRuns"; +export * from "./useRunTaskLogs"; +export * from "./useRunTaskResult"; +export * from "./useRunTasks"; +export * from "./useStartRun"; diff --git a/frontend/src/features/myWorkflows/api/runs/useRunReport.ts b/frontend/src/features/myWorkflows/api/runs/useRunReport.ts new file mode 100644 index 00000000..5bc81bd4 --- /dev/null +++ b/frontend/src/features/myWorkflows/api/runs/useRunReport.ts @@ -0,0 +1,49 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { skipToken, useQuery } from "@tanstack/react-query"; +import { type taskState } from "features/myWorkflows/types"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface WorkflowRunReportParams { + workflowId: string; + runId: string; + workspaceId: string; +} + +interface WorkflowRunReportResponse { + data: Array<{ + base64_content: string; + file_type: string; + piece_name: string; + dag_id: string; + duration: number; + start_date: string; + end_date: string; + execution_date: string; + task_id: string; + state: taskState; + }>; +} + +export const useRunReport = ( + { runId, workflowId, workspaceId }: Partial, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: ["RUN-REPORT", workspaceId, workflowId, runId], + queryFn: workspaceId + ? async () => + await getWorkflowRunReport({ runId, workflowId, workspaceId }) + : skipToken, + ...config, + }); +}; + +const getWorkflowRunReport = async ({ + workspaceId, + workflowId, + runId, +}: Partial): Promise => { + return await dominoApiClient.get( + `/workspaces/${workspaceId}/workflows/${workflowId}/runs/${runId}/tasks/report`, + ); +}; diff --git a/frontend/src/features/myWorkflows/api/runs/useRunTaskLogs.ts b/frontend/src/features/myWorkflows/api/runs/useRunTaskLogs.ts new file mode 100644 index 00000000..a6459f2c --- /dev/null +++ b/frontend/src/features/myWorkflows/api/runs/useRunTaskLogs.ts @@ -0,0 +1,62 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { skipToken, useQuery } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface RunTaskLogsParams { + workspaceId: string; + workflowId: string; + runId: string; + taskId: string; + taskTryNumber: string; +} + +export interface RunTaskLogsResponse { + data: string[]; + metadata?: PaginationMetadata; +} + +export const useRunTaskLogs = ( + { + workspaceId, + workflowId, + runId, + taskId, + taskTryNumber, + }: Partial, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: [ + "RUN-TASK-LOGS", + workspaceId, + workflowId, + runId, + taskId, + taskTryNumber, + ], + queryFn: + !workspaceId || !workflowId || !runId || !taskId || !taskTryNumber + ? skipToken + : async () => + await getWorkflowRunTaskLogs({ + workspaceId, + workflowId, + runId, + taskId, + taskTryNumber, + }), + ...config, + }); +}; + +const getWorkflowRunTaskLogs = async ({ + workspaceId, + workflowId, + runId, + taskId, + taskTryNumber, +}: RunTaskLogsParams): Promise => { + return await dominoApiClient.get( + `/workspaces/${workspaceId}/workflows/${workflowId}/runs/${runId}/tasks/${taskId}/${taskTryNumber}/logs`, + ); +}; diff --git a/frontend/src/features/myWorkflows/api/runs/useRunTaskResult.ts b/frontend/src/features/myWorkflows/api/runs/useRunTaskResult.ts new file mode 100644 index 00000000..7a7bb520 --- /dev/null +++ b/frontend/src/features/myWorkflows/api/runs/useRunTaskResult.ts @@ -0,0 +1,60 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { skipToken, useQuery } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +export interface WorkflowRunTaskResultParams { + workspaceId: string; + workflowId: string; + runId: string; + taskId: string; + taskTryNumber: string; +} + +export const useRunTaskResult = ( + { + runId, + taskId, + taskTryNumber, + workflowId, + workspaceId, + }: Partial, + config: QueryConfig<{ base64_content: string; file_type: string }> = {}, +) => { + return useQuery({ + queryKey: [ + "RUN-TASK-RESULTS", + workspaceId, + workflowId, + runId, + taskId, + taskTryNumber, + ], + queryFn: + !runId || !taskId || !taskTryNumber || !workflowId || !workspaceId + ? skipToken + : async () => + await getWorkflowRunTaskResult({ + runId, + taskId, + taskTryNumber, + workflowId, + workspaceId, + }), + ...config, + }); +}; + +const getWorkflowRunTaskResult = async ({ + workspaceId, + workflowId, + runId, + taskId, + taskTryNumber, +}: Partial): Promise<{ + base64_content: string; + file_type: string; +}> => { + return await dominoApiClient.get( + `/workspaces/${workspaceId}/workflows/${workflowId}/runs/${runId}/tasks/${taskId}/${taskTryNumber}/result`, + ); +}; diff --git a/frontend/src/features/myWorkflows/api/runs/useRunTasks.ts b/frontend/src/features/myWorkflows/api/runs/useRunTasks.ts new file mode 100644 index 00000000..2b89f4fc --- /dev/null +++ b/frontend/src/features/myWorkflows/api/runs/useRunTasks.ts @@ -0,0 +1,56 @@ +import { type IWorkflowRunTasks } from "@features/myWorkflows/types"; +import { type InfiniteQueryConfig } from "@services/clients/react-query.client"; +import { useInfiniteQuery } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface WorkflowRunTasksParams { + workspaceId: string; + workflowId: string; + runId: string; + page: number; + pageSize: number; +} + +interface WorkflowRunTasksResponse { + data: IWorkflowRunTasks[]; + metadata: PaginationMetadata; +} + +export const useRunTasks = ( + { + workspaceId, + workflowId, + runId, + }: Partial>, + config: InfiniteQueryConfig = {}, +) => { + return useInfiniteQuery({ + initialPageParam: 0, + queryKey: ["RUN-TASKS", workspaceId, workflowId, runId], + queryFn: async ({ pageParam }) => { + return await getWorkflowRunTasks({ + workspaceId: workspaceId as string, + workflowId: workflowId as string, + runId: runId as string, + page: pageParam, + pageSize: 100, + }); + }, + enabled: !!(workspaceId && workflowId && runId), + getNextPageParam: (res, _, page) => + res.metadata?.last_page === page ? page + 1 : page, + ...config, + }); +}; + +const getWorkflowRunTasks = async ({ + workspaceId, + workflowId, + runId, + page, + pageSize, +}: WorkflowRunTasksParams): Promise => { + return await dominoApiClient.get( + `/workspaces/${workspaceId}/workflows/${workflowId}/runs/${runId}/tasks?page=${page}&page_size=${pageSize}`, + ); +}; diff --git a/frontend/src/features/myWorkflows/api/runs/useRuns.ts b/frontend/src/features/myWorkflows/api/runs/useRuns.ts new file mode 100644 index 00000000..c4286299 --- /dev/null +++ b/frontend/src/features/myWorkflows/api/runs/useRuns.ts @@ -0,0 +1,42 @@ +import { type IWorkflowRuns } from "@features/myWorkflows/types"; +import { type QueryConfig } from "@services/clients/react-query.client"; +import { skipToken, useQuery } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface WorkflowRunParams { + workspaceId?: string; + workflowId?: string; + page: number; + pageSize: number; +} + +interface RunsResponse { + data: IWorkflowRuns[]; + metadata: PaginationMetadata; +} + +export const useRuns = ( + { workspaceId, workflowId, page = 0, pageSize = 10 }: WorkflowRunParams, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: ["RUNS", workspaceId, workflowId, page, pageSize], + queryFn: + !workspaceId || !workflowId + ? skipToken + : async () => + await getWorkflowRuns({ workspaceId, workflowId, page, pageSize }), + ...config, + }); +}; + +const getWorkflowRuns = async ({ + workspaceId, + workflowId, + page, + pageSize, +}: WorkflowRunParams): Promise => { + return await dominoApiClient.get( + `/workspaces/${workspaceId}/workflows/${workflowId}/runs?page=${page}&page_size=${pageSize}`, + ); +}; diff --git a/frontend/src/features/myWorkflows/api/runs/useStartRun.ts b/frontend/src/features/myWorkflows/api/runs/useStartRun.ts new file mode 100644 index 00000000..56511683 --- /dev/null +++ b/frontend/src/features/myWorkflows/api/runs/useStartRun.ts @@ -0,0 +1,39 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { type IPostWorkflowRunIdResponseInterface } from "features/myWorkflows/types/workflow"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface StartRunParams { + workflowId: string; +} + +interface UseStartRun { + workspaceId?: string; +} + +export const useStartRun = ( + { workspaceId }: UseStartRun, + config: MutationConfig< + StartRunParams, + IPostWorkflowRunIdResponseInterface + > = {}, +) => { + return useMutation({ + mutationFn: async ({ workflowId }) => { + if (!workflowId) throw new Error("no workspace selected"); + return await postWorkflowRunId({ workflowId, workspaceId }); + }, + ...config, + }); +}; + +const postWorkflowRunId = async ({ + workflowId, + workspaceId, +}: StartRunParams & + UseStartRun): Promise => { + return await dominoApiClient.post( + `/workspaces/${workspaceId}/workflows/${workflowId}/runs`, + null, + ); +}; diff --git a/frontend/src/features/myWorkflows/api/workflow/deleteWorkflowId.ts b/frontend/src/features/myWorkflows/api/workflow/deleteWorkflowId.ts deleted file mode 100644 index 1a9294d7..00000000 --- a/frontend/src/features/myWorkflows/api/workflow/deleteWorkflowId.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { AxiosError, type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { type IDeleteWorkflowIdResponseInterface } from "features/myWorkflows/types/workflow"; -import { toast } from "react-toastify"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface IDeleteWorkflowIdParams { - id: string; -} - -/** - * Get workflow by id using GET /workflow - * @returns workflow - */ -const deleteWorkflowId: ( - workspaceId: string, - params: IDeleteWorkflowIdParams, -) => Promise> = async ( - workspaceId, - params, -) => { - return await dominoApiClient.delete( - `/workspaces/${workspaceId}/workflows/${params.id}`, - ); -}; - -/** - * Delete workflow by id - * @returns authenticated delete function - */ -export const useAuthenticatedDeleteWorkflowId = () => { - const { workspace } = useWorkspaces(); - - if (!workspace) - throw new Error( - "Impossible to fetch delete without specifying a workspace", - ); - - const fetcher = async (params: IDeleteWorkflowIdParams) => - await deleteWorkflowId(workspace.id, params) - .then((data) => { - toast.success("Workflow deleted."); - return data; - }) - .catch((e) => { - if (e instanceof AxiosError) { - console.error(e); - } else { - throw e; - } - }); - return fetcher; -}; diff --git a/frontend/src/features/myWorkflows/api/workflow/getWorkflow.ts b/frontend/src/features/myWorkflows/api/workflow/getWorkflow.ts deleted file mode 100644 index f4f9fe5b..00000000 --- a/frontend/src/features/myWorkflows/api/workflow/getWorkflow.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { type IGetWorkflowResponseInterface } from "features/myWorkflows/types/workflow"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -const getWorkflowsUrl = (workspace: string, page: number, pageSize: number) => - `/workspaces/${workspace}/workflows?page=${page}&page_size=${pageSize}`; - -/** - * Get workflows using GET /workflows - * @param token auth token (string) - * @returns workflow - */ -const getWorkflows: ( - workspace: string, - page: number, - pageSize: number, -) => Promise> = async ( - workspace, - page, - pageSize, -) => { - return await dominoApiClient.get(getWorkflowsUrl(workspace, page, pageSize)); -}; - -/** - * Get workflow - * @returns workflow as swr response - */ -export const useAuthenticatedGetWorkflows = ( - page: number = 0, - pageSize: number = 5, -) => { - const { workspace } = useWorkspaces(); - - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - const fetcher = async () => - await getWorkflows(workspace.id, page, pageSize).then((data) => data.data); - - return useSWR( - getWorkflowsUrl(workspace.id, page, pageSize), - async () => await fetcher(), - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }, - ); -}; diff --git a/frontend/src/features/myWorkflows/api/workflow/getWorkflowId.ts b/frontend/src/features/myWorkflows/api/workflow/getWorkflowId.ts deleted file mode 100644 index c734f8e3..00000000 --- a/frontend/src/features/myWorkflows/api/workflow/getWorkflowId.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { type IGetWorkflowIdResponseInterface } from "features/myWorkflows/types/workflow"; -import { dominoApiClient } from "services/clients/domino.client"; -import useSWR from "swr"; - -interface IGetWorkflowIdParams { - id?: string; -} - -const getWorkflowUrl = (workspaceId: string, id?: string) => - id ? `/workspaces/${workspaceId}/workflows/${id}` : null; - -/** - * Get workflow by id using GET /workflow - * @returns workflow - */ -const getWorkflowId: ( - workspaceId: string, - params: IGetWorkflowIdParams, -) => Promise< - AxiosResponse | undefined -> = async (workspaceId, params) => { - const url = getWorkflowUrl(workspaceId, params.id); - if (url) { - return await dominoApiClient.get(url); - } -}; - -/** - * Get workflow by id - * @param params `{ workspaceId: number, id: string }` - * @returns workflow fetcher fn - */ -export const useAuthenticatedGetWorkflowId = ({ id }: IGetWorkflowIdParams) => { - const { workspace } = useWorkspaces(); - - if (!workspace) - throw new Error( - "Impossible to fetch workflows without specifying a workspace", - ); - - // todo add swr ? - const fetcher = async (params: IGetWorkflowIdParams) => { - return await getWorkflowId(workspace.id, params).then((data) => data?.data); - }; - - const key = getWorkflowUrl(workspace.id, id); - - return useSWR(key, async () => await fetcher({ id }), { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }); -}; diff --git a/frontend/src/features/myWorkflows/api/workflow/index.ts b/frontend/src/features/myWorkflows/api/workflow/index.ts index 7164b493..fc6f95aa 100644 --- a/frontend/src/features/myWorkflows/api/workflow/index.ts +++ b/frontend/src/features/myWorkflows/api/workflow/index.ts @@ -1,5 +1,3 @@ -export * from "./deleteWorkflowId"; -export * from "./getWorkflowId"; -export * from "./getWorkflow"; -export * from "./postWorkflowRunId"; -export * from "./postWorkflow"; +export * from "./useDeleteWorkflow"; +export * from "./useWorkflow"; +export * from "./useWorkflows"; diff --git a/frontend/src/features/myWorkflows/api/workflow/postWorkflow.ts b/frontend/src/features/myWorkflows/api/workflow/postWorkflow.ts deleted file mode 100644 index 1c1bd23d..00000000 --- a/frontend/src/features/myWorkflows/api/workflow/postWorkflow.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { type AxiosResponse } from "axios"; -import { type CreateWorkflowRequest } from "features/workflowEditor/context/types"; -import { type IPostWorkflowResponseInterface } from "features/myWorkflows/types"; -import { dominoApiClient } from "services/clients/domino.client"; - -export interface IPostWorkflowParams extends CreateWorkflowRequest { - workspace_id: string; -} - -/** - * Create workflow using POST /workflow - * @returns ? - */ -const postWorkflow: ( - payload: IPostWorkflowParams, -) => Promise> = async ( - payload, -) => { - return await dominoApiClient.post( - `/workspaces/${payload.workspace_id}/workflows`, - payload, - ); -}; - -/** - * Create authenticated workflow - * @param params `{ id: string, data: Record }`` - * @returns crate workflow function - */ -export const useAuthenticatedPostWorkflow = () => { - const fetcher = async (params: IPostWorkflowParams) => - await postWorkflow(params).then((data) => data.data); - - return fetcher; -}; diff --git a/frontend/src/features/myWorkflows/api/workflow/postWorkflowRunId.ts b/frontend/src/features/myWorkflows/api/workflow/postWorkflowRunId.ts deleted file mode 100644 index 12517a8e..00000000 --- a/frontend/src/features/myWorkflows/api/workflow/postWorkflowRunId.ts +++ /dev/null @@ -1,56 +0,0 @@ -// TODO move to /runs -import { AxiosError, type AxiosResponse } from "axios"; -import { useWorkspaces } from "context/workspaces"; -import { type IPostWorkflowRunIdResponseInterface } from "features/myWorkflows/types/workflow"; -import { toast } from "react-toastify"; -import { dominoApiClient } from "services/clients/domino.client"; - -interface IPostWorkflowRunIdParams { - id: string; -} - -const postWorkflowRunUrl = (workspaceId: string, id: string) => - `/workspaces/${workspaceId}/workflows/${id}/runs`; - -/** - * Run workflow by id using /workflow/run/:id - * @returns workflow run result - */ -const postWorkflowRunId: ( - workspaceId: string, - params: IPostWorkflowRunIdParams, -) => Promise> = async ( - workspaceId, - params, -) => { - return await dominoApiClient.post( - postWorkflowRunUrl(workspaceId, params.id), - null, - ); -}; - -/** - * Run workflow by id fetcher fn - * @param params `{ id: string }` - */ -export const useAuthenticatedPostWorkflowRunId = () => { - const { workspace } = useWorkspaces(); - - if (!workspace) return async (_params: IPostWorkflowRunIdParams) => {}; - - const fetcher = async (params: IPostWorkflowRunIdParams) => - await postWorkflowRunId(workspace.id, params) - .then((data) => { - toast.success("Workflow started"); - return data; - }) - .catch((e) => { - if (e instanceof AxiosError) { - console.error(e); - } else { - throw e; - } - }); - - return fetcher; -}; diff --git a/frontend/src/features/myWorkflows/api/workflow/useDeleteWorkflow.ts b/frontend/src/features/myWorkflows/api/workflow/useDeleteWorkflow.ts new file mode 100644 index 00000000..e2996ac8 --- /dev/null +++ b/frontend/src/features/myWorkflows/api/workflow/useDeleteWorkflow.ts @@ -0,0 +1,42 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { type IDeleteWorkflowIdResponseInterface } from "features/myWorkflows/types/workflow"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface DeleteWorkflowParams { + workflowId: string; +} + +interface UseDeleteWorkflow { + workspaceId?: string; +} + +export const useDeleteWorkflow = ( + { workspaceId }: UseDeleteWorkflow, + config: MutationConfig = {}, +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({ workflowId }) => { + if (!workspaceId) throw new Error("No workspace selected"); + await deleteWorkflowById({ workflowId, workspaceId }); + }, + onSuccess: async (_, { workflowId }) => { + await queryClient.invalidateQueries({ + queryKey: ["WORKFLOWS", workspaceId], + }); + await queryClient.invalidateQueries({ + queryKey: ["WORKFLOW", workspaceId, workflowId], + }); + }, + ...config, + }); +}; + +const deleteWorkflowById = async ( + params: DeleteWorkflowParams & UseDeleteWorkflow, +): Promise => + await dominoApiClient.delete( + `/workspaces/${params.workspaceId}/workflows/${params.workflowId}`, + ); diff --git a/frontend/src/features/myWorkflows/api/workflow/useWorkflow.ts b/frontend/src/features/myWorkflows/api/workflow/useWorkflow.ts new file mode 100644 index 00000000..5924dd8c --- /dev/null +++ b/frontend/src/features/myWorkflows/api/workflow/useWorkflow.ts @@ -0,0 +1,34 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { useQuery, skipToken } from "@tanstack/react-query"; +import { type IGetWorkflowIdResponseInterface } from "features/myWorkflows/types/workflow"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface GetWorkflowByIdParams { + workspaceId: string; + workflowId: string; +} + +export const useWorkflow = ( + { workflowId, workspaceId }: Partial, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: ["WORKFLOW", workspaceId, workflowId], + queryFn: + workspaceId && workflowId + ? async () => await getWorkflowById({ workflowId, workspaceId }) + : skipToken, + ...config, + }); +}; + +const getWorkflowById: ( + params: GetWorkflowByIdParams, +) => Promise = async ({ + workspaceId, + workflowId, +}) => { + return await dominoApiClient.get( + `/workspaces/${workspaceId}/workflows/${workflowId}`, + ); +}; diff --git a/frontend/src/features/myWorkflows/api/workflow/useWorkflows.ts b/frontend/src/features/myWorkflows/api/workflow/useWorkflows.ts new file mode 100644 index 00000000..71d327c3 --- /dev/null +++ b/frontend/src/features/myWorkflows/api/workflow/useWorkflows.ts @@ -0,0 +1,32 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { useQuery, skipToken } from "@tanstack/react-query"; +import { type IGetWorkflowResponseInterface } from "features/myWorkflows/types/workflow"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface GetWorkflowsParams { + workspaceId: string; + page: number; + pageSize: number; +} + +export const useWorkflows = ( + { page = 0, pageSize = 5, workspaceId }: Partial, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: ["WORKFLOWS", workspaceId, page, pageSize], + queryFn: workspaceId + ? async () => await getWorkflows({ workspaceId, page, pageSize }) + : skipToken, + ...config, + }); +}; + +const getWorkflows = async ({ + workspaceId, + page, + pageSize, +}: GetWorkflowsParams): Promise => + await dominoApiClient.get( + `/workspaces/${workspaceId}/workflows?page=${page}&page_size=${pageSize}`, + ); diff --git a/frontend/src/features/myWorkflows/components/ResultsReport/index.tsx b/frontend/src/features/myWorkflows/components/ResultsReport/index.tsx index 24aeb9b9..ada0fa96 100644 --- a/frontend/src/features/myWorkflows/components/ResultsReport/index.tsx +++ b/frontend/src/features/myWorkflows/components/ResultsReport/index.tsx @@ -1,3 +1,4 @@ +import { useWorkspaces } from "@context/workspaces"; import LogoutIcon from "@mui/icons-material/Logout"; import { Button, @@ -17,10 +18,7 @@ import { import { DownloadAsPDF } from "components/DownloadPDF"; import dayjs from "dayjs"; import duration from "dayjs/plugin/duration"; -import { - useAuthenticatedGetWorkflowId, - useAuthenticatedGetWorkflowRunResultReport, -} from "features/myWorkflows/api"; +import { useWorkflow, useRunReport } from "features/myWorkflows/api"; import React, { useCallback, useMemo } from "react"; import { useNavigate, useParams } from "react-router-dom"; @@ -32,9 +30,9 @@ dayjs.extend(duration); export const ResultsReport: React.FC = () => { const { id, runId } = useParams<{ id: string; runId: string }>(); - + const { workspace } = useWorkspaces(); const navigate = useNavigate(); - const { data } = useAuthenticatedGetWorkflowRunResultReport({ + const { data } = useRunReport({ workflowId: id, runId, }); @@ -48,8 +46,9 @@ export const ResultsReport: React.FC = () => { } }, []); - const { data: workflow } = useAuthenticatedGetWorkflowId({ - id: id as string, + const { data: workflow } = useWorkflow({ + workflowId: id, + workspaceId: workspace?.id, }); const { startDate, endDate, duration } = useMemo(() => { @@ -113,7 +112,7 @@ export const ResultsReport: React.FC = () => { {data?.data.map((task, idx) => ( - <> +
{ {idx !== data?.data.length - 1 ? : null} - +
))}
; - refreshTaskLogs: KeyedMutator< - | { - data: string[]; - } - | undefined - >; -} +export const WorkflowRunDetail: React.FC = ({ + autoUpdate, + runId, + nodeId, + tasks, + workflowId, +}) => { + const [value, setValue] = useState(0); -export const WorkflowRunDetail = forwardRef( - ({ runId, nodeId, tasks, workflowId }, ref) => { - const [value, setValue] = useState(0); + const taskData = useMemo(() => { + if (nodeId) { + const task = tasks?.find((task) => { + return task.task_id === nodeId; + }); - const taskData = useMemo(() => { - if (nodeId) { - const task = tasks?.find((task) => { - return task.task_id === nodeId; - }); + return task; + } + }, [runId, nodeId, tasks]); - return task; - } - }, [runId, nodeId, tasks]); + const { workspace } = useWorkspaces(); - const { data: taskLogs, mutate: refreshTaskLogs } = - useAuthenticatedGetWorkflowRunTaskLogs({ - runId: runId ?? "", - taskId: taskData?.task_id ?? "", - taskTryNumber: String(taskData?.try_number) ?? "", - workflowId: workflowId ?? "", - }); - - const { - data: taskResult, - isLoading, - mutate: refreshTaskResults, - } = useAuthenticatedGetWorkflowRunTaskResult({ + const { data: taskLogs } = useRunTaskLogs( + { + workspaceId: workspace?.id, + workflowId, runId, - taskId: taskData?.state === "success" ? taskData?.task_id : undefined, + taskId: taskData?.task_id, taskTryNumber: String(taskData?.try_number), - workflowId, - }); + }, + { + refetchInterval: autoUpdate ? 1500 : undefined, + }, + ); - const handleChange = useCallback( - (_event: React.SyntheticEvent, newValue: number) => { - setValue(newValue); - }, - [], - ); + const { data: taskResult, isLoading } = useRunTaskResult({ + workspaceId: workspace?.id, + workflowId, + runId, + taskId: taskData?.state === "success" ? taskData?.task_id : undefined, + taskTryNumber: String(taskData?.try_number), + }); - useImperativeHandle(ref, () => ({ - refreshTaskResults, - refreshTaskLogs, - })); + const handleChange = useCallback( + (_event: React.SyntheticEvent, newValue: number) => { + setValue(newValue); + }, + [], + ); - return ( - - {runId ? ( - nodeId ? ( - - {taskData && ( - <> - - - - - - - - - - - )} - - ) : ( - - - Select a domino piece - - - ) + return ( + + {runId ? ( + nodeId ? ( + + {taskData && ( + <> + + + + + + + + + + + )} + ) : ( - - )} - - ); - }, -); - -WorkflowRunDetail.displayName = "WorkflowRunDetail"; + + + Select a domino piece + + + ) + ) : ( + + )} + + ); +}; diff --git a/frontend/src/features/myWorkflows/components/WorkflowDetail/WorkflowRunsTable.tsx b/frontend/src/features/myWorkflows/components/WorkflowDetail/WorkflowRunsTable.tsx index 9913b37e..a6af8809 100644 --- a/frontend/src/features/myWorkflows/components/WorkflowDetail/WorkflowRunsTable.tsx +++ b/frontend/src/features/myWorkflows/components/WorkflowDetail/WorkflowRunsTable.tsx @@ -1,16 +1,11 @@ +import { useWorkspaces } from "@context/workspaces"; import AssessmentIcon from "@mui/icons-material/Assessment"; import { Card, Grid, IconButton, Skeleton, Tooltip } from "@mui/material"; import { DataGrid, type GridColDef } from "@mui/x-data-grid"; import { NoDataOverlay } from "components/NoDataOverlay"; -import { useAuthenticatedGetWorkflowRuns } from "features/myWorkflows/api"; +import { useRuns } from "features/myWorkflows/api"; import { type IWorkflowRuns } from "features/myWorkflows/types"; -import React, { - forwardRef, - useEffect, - useImperativeHandle, - useMemo, - useState, -} from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { secondsToHMS } from "utils"; @@ -18,6 +13,7 @@ import { States } from "./States"; import { WorkflowRunTableFooter } from "./WorkflowRunTableFooter"; interface Props { + autoUpdate: boolean; workflowId: string; selectedRun: IWorkflowRuns | null; onSelectedRunChange: (run: IWorkflowRuns | null) => void; @@ -25,86 +21,84 @@ interface Props { refresh: () => void; } -export interface WorkflowRunsTableRef { - refetchWorkflowsRun: () => void; -} +export const WorkflowRunsTable: React.FC = ({ + autoUpdate, + workflowId, + selectedRun, + onSelectedRunChange: setSelectedRun, + triggerRun, + refresh, +}) => { + const navigation = useNavigate(); + const [paginationModel, setPaginationModel] = useState({ + pageSize: 10, + page: 0, + }); -export const WorkflowRunsTable = forwardRef( - ( - { - workflowId, - selectedRun, - onSelectedRunChange: setSelectedRun, - triggerRun, - refresh, - }, - ref, - ) => { - const navigation = useNavigate(); - const [paginationModel, setPaginationModel] = useState({ - pageSize: 10, - page: 0, - }); + const { workspace } = useWorkspaces(); - const { - data: workflowRuns, - isLoading, - mutate: refetchWorkflowsRun, - } = useAuthenticatedGetWorkflowRuns({ + const { data: workflowRuns, isLoading } = useRuns( + { + workspaceId: workspace?.id, page: paginationModel.page, pageSize: paginationModel.pageSize, workflowId, - }); + }, + { + refetchInterval: autoUpdate ? 1500 : undefined, + }, + ); - const columns = useMemo>>( - () => [ - { - field: "start_date", - headerName: "Start Date", - headerAlign: "center", - align: "center", - type: "string", - flex: 1, - minWidth: 150, - valueFormatter: ({ value }) => new Date(value).toLocaleString(), - }, - { - field: "end_date", - headerName: "End Date", - headerAlign: "center", - align: "center", - type: "string", - flex: 1, - minWidth: 150, - valueFormatter: ({ value }) => new Date(value).toLocaleString(), - }, - { - field: "duration_in_seconds", - headerName: "Duration", - headerAlign: "center", - align: "center", - minWidth: 150, - flex: 1, - valueFormatter: ({ value }) => (value ? secondsToHMS(value) : "N/A"), + const columns = useMemo>>( + () => [ + { + field: "start_date", + headerName: "Start Date", + headerAlign: "center", + align: "center", + type: "string", + flex: 1, + minWidth: 150, + valueFormatter: ({ value }) => new Date(value).toLocaleString(), + }, + { + field: "end_date", + headerName: "End Date", + headerAlign: "center", + align: "center", + type: "string", + flex: 1, + minWidth: 150, + valueFormatter: ({ value }) => new Date(value).toLocaleString(), + }, + { + field: "duration_in_seconds", + headerName: "Duration", + headerAlign: "center", + align: "center", + minWidth: 150, + flex: 1, + valueFormatter: ({ value }) => (value ? secondsToHMS(value) : "N/A"), + }, + { + field: "state", + headerName: "State", + headerAlign: "center", + align: "center", + type: "string", + minWidth: 150, + // flex: 1, + renderCell: (params) => { + return ; }, - { - field: "state", - headerName: "State", - headerAlign: "center", - align: "center", - type: "string", - minWidth: 150, - // flex: 1, - renderCell: (params) => { - return ; - }, - }, - { - field: "actions", - headerName: "", - maxWidth: 10, - renderCell: ({ row }) => ( - + }, + { + field: "actions", + headerName: "", + maxWidth: 10, + renderCell: ({ row }) => ( + + { navigation( @@ -115,100 +109,93 @@ export const WorkflowRunsTable = forwardRef( > - - ), - headerAlign: "center", - align: "center", - sortable: false, - }, - ], - [], - ); - - const { rows, totalRows } = useMemo( - () => ({ - // every column need a id prop in DataGrid component - rows: - workflowRuns?.data?.map((wr) => ({ - ...wr, - id: wr.workflow_run_id, - })) ?? [], - totalRows: workflowRuns?.metadata?.total ?? 0, - }), - [workflowRuns], - ); + + + ), + headerAlign: "center", + align: "center", + sortable: false, + }, + ], + [], + ); - useImperativeHandle(ref, () => ({ - refetchWorkflowsRun, - })); + const { rows, totalRows } = useMemo( + () => ({ + // every column need a id prop in DataGrid component + rows: + workflowRuns?.data?.map((wr) => ({ + ...wr, + id: wr.workflow_run_id, + })) ?? [], + totalRows: workflowRuns?.metadata?.total ?? 0, + }), + [workflowRuns], + ); - useEffect(() => { - if (!isLoading && workflowRuns?.data && workflowRuns?.data?.length > 0) { - setSelectedRun(workflowRuns.data[0]); - } - }, [isLoading, workflowRuns]); + useEffect(() => { + if (!isLoading && workflowRuns?.data && workflowRuns?.data?.length > 0) { + setSelectedRun(workflowRuns.data[0]); + } + }, [isLoading, workflowRuns]); - return ( - - - - {isLoading ? ( - - ) : ( - { - setSelectedRun( - workflowRuns?.data?.find( - (wr) => wr.workflow_run_id === id, - ) ?? null, - ); - }} - rowSelectionModel={ - selectedRun ? [selectedRun.workflow_run_id] : [] - } - columns={columns} - rows={rows} - pagination - paginationMode="server" - pageSizeOptions={[5, 10, 25]} - initialState={{ - pagination: { - paginationModel, - }, - }} - rowCount={totalRows} - onPaginationModelChange={setPaginationModel} - disableDensitySelector - hideFooterSelectedRowCount - disableColumnMenu - disableColumnSelector - slots={{ - noRowsOverlay: NoDataOverlay, - footer: WorkflowRunTableFooter, - }} - slotProps={{ - footer: { triggerRun, refresh }, - }} - sx={{ - "&.MuiDataGrid-root .MuiDataGrid-cell:focus": { - outline: "none", - }, - "& .MuiDataGrid-row:hover": { - cursor: "pointer", - }, - }} - /> - )} - - + return ( + + + + {isLoading ? ( + + ) : ( + { + setSelectedRun( + workflowRuns?.data?.find((wr) => wr.workflow_run_id === id) ?? + null, + ); + }} + rowSelectionModel={ + selectedRun ? [selectedRun.workflow_run_id] : [] + } + columns={columns} + rows={rows} + pagination + paginationMode="server" + pageSizeOptions={[5, 10, 25]} + initialState={{ + pagination: { + paginationModel, + }, + }} + rowCount={totalRows} + onPaginationModelChange={setPaginationModel} + disableDensitySelector + hideFooterSelectedRowCount + disableColumnMenu + disableColumnSelector + slots={{ + noRowsOverlay: NoDataOverlay, + footer: WorkflowRunTableFooter, + }} + slotProps={{ + footer: { triggerRun, refresh }, + }} + sx={{ + "&.MuiDataGrid-root .MuiDataGrid-cell:focus": { + outline: "none", + }, + "& .MuiDataGrid-row:hover": { + cursor: "pointer", + }, + }} + /> + )} + - ); - }, -); - -WorkflowRunsTable.displayName = "WorkflowRunsTable"; + + ); +}; diff --git a/frontend/src/features/myWorkflows/components/WorkflowDetail/index.tsx b/frontend/src/features/myWorkflows/components/WorkflowDetail/index.tsx index 2369001c..ee76ac21 100644 --- a/frontend/src/features/myWorkflows/components/WorkflowDetail/index.tsx +++ b/frontend/src/features/myWorkflows/components/WorkflowDetail/index.tsx @@ -1,39 +1,37 @@ -import { Grid, Paper } from "@mui/material"; -import { Breadcrumbs } from "components/Breadcrumbs"; -import { - useAuthenticatedGetWorkflowId, - useAuthenticatedGetWorkflowRunTasks, - useAuthenticatedPostWorkflowRunId, -} from "features/myWorkflows/api"; +import { useWorkspaces } from "@context/workspaces"; import { + useWorkflow, type IWorkflowRuns, type IWorkflowRunTasks, -} from "features/myWorkflows/types"; -import { type DefaultNode } from "features/workflowEditor/components/Panel/WorkflowPanel"; -import React, { useCallback, useEffect, useRef, useState } from "react"; + useRunTasks, + useStartRun, +} from "@features/myWorkflows"; +import { type DefaultNode } from "@features/workflowEditor/components/Panel/WorkflowPanel"; +import { Grid, Paper } from "@mui/material"; +import { useQueryClient } from "@tanstack/react-query"; +import { Breadcrumbs } from "components/Breadcrumbs"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; import { useParams } from "react-router-dom"; +import { toast } from "react-toastify"; import { type NodeMouseHandler } from "reactflow"; -import { useInterval } from "utils"; import { WorkflowPanel, type WorkflowPanelRef, type RunNode, } from "./WorkflowPanel"; -import { - WorkflowRunDetail, - type WorkflowRunDetailRef, -} from "./WorkflowRunDetail"; -import { - WorkflowRunsTable, - type WorkflowRunsTableRef, -} from "./WorkflowRunsTable"; +import { WorkflowRunDetail } from "./WorkflowRunDetail"; +import { WorkflowRunsTable } from "./WorkflowRunsTable"; /** * @todo Cancel run. [] * @todo Pause run. [] - * @todo Show piece logs [ ] - * @todo Show result [ ] * @todo add break interval when workflow is not running */ @@ -48,129 +46,98 @@ export const WorkflowDetail: React.FC = () => { const [selectedRun, setSelectedRun] = useState(null); const [statusTasks, setTasks] = useState([]); + const { workspace } = useWorkspaces(); + const queryClient = useQueryClient(); + const workflowPanelRef = useRef(null); - const workflowRunsTableRef = useRef(null); - const workflowRunDetailRef = useRef(null); - const { data: workflow } = useAuthenticatedGetWorkflowId({ - id: id as string, + const { data: workflow } = useWorkflow({ + workspaceId: workspace?.id, + workflowId: id as string, }); - const fetchWorkflowTasks = useAuthenticatedGetWorkflowRunTasks(); - const handleRunWorkflow = useAuthenticatedPostWorkflowRunId(); - - const triggerRun = () => { - if (workflow?.id) { - void handleRunWorkflow({ id: String(workflow.id) }); - setInterval(() => { - setAutoUpdate(true); - }, 1500); - } - }; + const { data: allTasks } = useRunTasks( + { + workspaceId: workspace?.id, + workflowId: id as string, + runId: selectedRun?.workflow_run_id, + }, + { + refetchInterval: autoUpdate ? 1500 : undefined, + }, + ); - const refreshDetails = useCallback(() => { - void workflowRunDetailRef.current?.refreshTaskLogs(); - void workflowRunDetailRef.current?.refreshTaskResults(); - }, [workflowRunDetailRef]); - - const refreshTable = useCallback(() => { - void workflowRunsTableRef.current?.refetchWorkflowsRun(); - }, [workflowRunsTableRef]); - - const refreshTasks = useCallback(async () => { - if (selectedRun && workflow) { - try { - const pageSize = 100; - const result = await fetchWorkflowTasks({ - workflowId: id as string, - runId: selectedRun.workflow_run_id, - page: 0, - pageSize, + const { mutateAsync: handleRunWorkflow } = useStartRun( + { + workspaceId: workspace?.id, + }, + { + onSuccess: async (_, { workflowId }) => { + await queryClient.invalidateQueries({ + queryKey: ["RUNS", workspace?.id, workflowId], }); - const { metadata } = result; - const total = metadata?.total ? metadata.total : 0; - - const allTasks = [result]; - - if (total > pageSize) { - const numberOfPages = Math.ceil(total / pageSize); - const pages = Array.from(Array(numberOfPages).keys()).slice(1); - const promises = pages.map( - async (page) => - await fetchWorkflowTasks({ - workflowId: id as string, - runId: selectedRun.workflow_run_id, - page, - pageSize, - }), - ); - const responses = await Promise.all(promises); - allTasks.push(...responses); - } - - const nodes: RunNode[] = []; - const tasks: IWorkflowRunTaskExtended[] = []; - for (const result of allTasks) { - const { data } = result; - - if (Array.isArray(data)) { - const nodesData = data - .map((task) => { - const defaultNode: DefaultNode | undefined = workflow.ui_schema - .nodes[task.task_id] as DefaultNode | undefined; - const runNode = { ...defaultNode } as unknown as RunNode; - - if (runNode?.data) { - runNode.data.taskId = task.task_id; - runNode.data.state = task.state; - } - return runNode as unknown as RunNode; - }) - .filter((n) => !!n); - const tasksData = data - .map((task) => { - const node: DefaultNode | undefined = workflow.ui_schema.nodes[ - task.task_id - ] as DefaultNode | undefined; - - const pieceName = node?.data?.style?.label ?? node?.data?.name; - return { - ...task, - pieceName, - } as unknown as IWorkflowRunTaskExtended; - }) - .filter((n) => !!n); - tasks.push(...tasksData); - nodes.push(...nodesData); - } - } - const currentTaks = JSON.stringify(statusTasks); - const newTasks = JSON.stringify(tasks); - - if (currentTaks !== newTasks) { - setTasks(tasks); - } + setAutoUpdate(true); + toast.success("Workflow run started"); + }, + }, + ); - const currentNodes = JSON.stringify( - workflowPanelRef.current?.nodes ?? {}, - ); - const newNodes = JSON.stringify(nodes); - if (newNodes !== currentNodes) { - // need to create a different object to perform a re-render - workflowPanelRef.current?.setNodes(JSON.parse(newNodes)); - workflowPanelRef.current?.setEdges(workflow.ui_schema.edges); + const { nodes, edges, tasks } = useMemo(() => { + const edges = workflow?.ui_schema.edges ?? []; + const nodes: RunNode[] = []; + const tasks: IWorkflowRunTaskExtended[] = []; + if (selectedRun && workflow && allTasks?.pages) { + for (const result of allTasks.pages ?? []) { + const { data } = result; + + if (Array.isArray(data)) { + const nodesData = data + .map((task) => { + const defaultNode: DefaultNode | undefined = + workflow.ui_schema.nodes[task.task_id]; + const runNode = { ...defaultNode } as unknown as RunNode; + + if (runNode?.data) { + runNode.data.taskId = task.task_id; + runNode.data.state = task.state; + } + return runNode as unknown as RunNode; + }) + .filter((n) => !!n); + const tasksData = data + .map((task) => { + const node: DefaultNode | undefined = + workflow.ui_schema.nodes[task.task_id]; + + const pieceName = node?.data?.style?.label ?? node?.data?.name; + return { + ...task, + pieceName, + } as unknown as IWorkflowRunTaskExtended; + }) + .filter((n) => !!n); + tasks.push(...tasksData); + nodes.push(...nodesData); } - } catch (e) { - console.log(e); } } - }, [workflow, fetchWorkflowTasks, selectedRun]); + return { nodes, edges, tasks }; + }, [allTasks, workflow]); - const refresh = useCallback(async () => { - refreshDetails(); - refreshTable(); - await refreshTasks(); + const triggerRun = async () => { + if (workflow?.id) { + await handleRunWorkflow({ workflowId: String(workflow.id) }); + setSelectedRun(null); + } + }; + useEffect(() => { + workflowPanelRef.current?.setNodes(nodes); + workflowPanelRef.current?.setEdges(edges); + setTasks(tasks); + }, [nodes, edges, tasks]); + + const refresh = useCallback(async () => { if ( selectedRun && (selectedRun.state === "success" || selectedRun.state === "failed") @@ -179,15 +146,12 @@ export const WorkflowDetail: React.FC = () => { } else { setAutoUpdate(true); } - }, [refreshDetails, refreshTable, refreshTasks, selectedRun, setAutoUpdate]); + }, [selectedRun, setAutoUpdate]); - const handleSelectRun = useCallback( - (run: IWorkflowRuns | null) => { - setSelectedRun(run); - setAutoUpdate(true); - }, - [refreshDetails, refreshTable, refreshTasks], - ); + const handleSelectRun = useCallback((run: IWorkflowRuns | null) => { + setSelectedRun(run); + setAutoUpdate(true); + }, []); const onNodeDoubleClick = useCallback( (_, node: RunNode) => { @@ -196,16 +160,6 @@ export const WorkflowDetail: React.FC = () => { [], ); - useEffect(() => { - if (selectedRun) { - refresh().catch((e) => { - console.log(e); - }); - } - }, [selectedRun, refresh]); - - useInterval(refresh, 3000, autoUpdate); - return ( @@ -217,10 +171,10 @@ export const WorkflowDetail: React.FC = () => { {/* WorkflowRunsTable */} @@ -239,7 +193,7 @@ export const WorkflowDetail: React.FC = () => { {/* Right Column */} { page: 0, }); + const { workspace } = useWorkspaces(); + const queryClient = useQueryClient(); + const { data: workflows, isLoading, - mutate: handleRefreshWorkflows, - } = useAuthenticatedGetWorkflows( - paginationModel.page, - paginationModel.pageSize, + refetch: handleRefreshWorkflows, + } = useWorkflows( + { + workspaceId: workspace?.id, + page: paginationModel.page, + pageSize: paginationModel.pageSize, + }, + { + refetchInterval: 5000, + }, ); - const handleDeleteWorkflow = useAuthenticatedDeleteWorkflowId(); - const handleRunWorkflow = useAuthenticatedPostWorkflowRunId(); + const { mutateAsync: handleDeleteWorkflow } = useDeleteWorkflow( + { + workspaceId: workspace?.id, + }, + { + onSuccess: () => { + toast.success("Workflow deleted"); + }, + }, + ); + + const { mutateAsync: handleRunWorkflow } = useStartRun( + { + workspaceId: workspace?.id, + }, + { + onSuccess: async (_, { workflowId }) => { + await queryClient.invalidateQueries({ + queryKey: ["RUNS", workspace?.id, workflowId], + }); + toast.success("Workflow run started"); + }, + }, + ); const deleteWorkflow = useCallback(async (id: IWorkflow["id"]) => { try { - await handleDeleteWorkflow({ id: String(id) }); + await handleDeleteWorkflow({ workflowId: String(id) }); await handleRefreshWorkflows(); } catch (e) { console.error(e); @@ -56,7 +88,7 @@ export const WorkflowList: React.FC = () => { }, []); const runWorkflow = useCallback(async (id: IWorkflow["id"]) => { try { - await handleRunWorkflow({ id: String(id) }); + await handleRunWorkflow({ workflowId: String(id) }); } catch (e) { console.error(e); } @@ -95,14 +127,14 @@ export const WorkflowList: React.FC = () => { { field: "name", headerName: "Workflow Name", flex: 2, minWidth: 220 }, { field: "start_date", - headerName: ( + renderHeader: () => ( Start Date{" "} - ) as any, + ), flex: 1, align: "center", minWidth: 220, @@ -112,14 +144,14 @@ export const WorkflowList: React.FC = () => { }, { field: "end_date", - headerName: ( + renderHeader: () => ( End Date{" "} - ) as any, + ), headerAlign: "center", align: "center", type: "string", @@ -217,8 +249,6 @@ export const WorkflowList: React.FC = () => { [navigate], ); - useInterval(handleRefreshWorkflows, 5000); - if (isLoading) { return ; } diff --git a/frontend/src/features/myWorkflows/index.ts b/frontend/src/features/myWorkflows/index.ts index 775b30b7..8eda34a8 100644 --- a/frontend/src/features/myWorkflows/index.ts +++ b/frontend/src/features/myWorkflows/index.ts @@ -1,2 +1,3 @@ export * from "./api"; -export * from "./pages"; +export * from "./routes"; +export * from "./types"; diff --git a/frontend/src/features/myWorkflows/pages/ResultsReportPage.tsx b/frontend/src/features/myWorkflows/pages/ResultsReportPage.tsx index 39d9e6a9..751d8adf 100644 --- a/frontend/src/features/myWorkflows/pages/ResultsReportPage.tsx +++ b/frontend/src/features/myWorkflows/pages/ResultsReportPage.tsx @@ -1,17 +1,14 @@ import { Grid } from "@mui/material"; -import PrivateLayout from "components/PrivateLayout"; import React from "react"; import { ResultsReport } from "../components/ResultsReport"; export const ResultsReportPage: React.FC = () => { return ( - - - - - + + + - + ); }; diff --git a/frontend/src/features/myWorkflows/pages/WorkflowDetailPage.tsx b/frontend/src/features/myWorkflows/pages/WorkflowDetailPage.tsx index 0815376f..5805abe3 100644 --- a/frontend/src/features/myWorkflows/pages/WorkflowDetailPage.tsx +++ b/frontend/src/features/myWorkflows/pages/WorkflowDetailPage.tsx @@ -1,5 +1,4 @@ import { Grid } from "@mui/material"; -import PrivateLayout from "components/PrivateLayout"; import { WorkflowDetail } from "../components/WorkflowDetail"; @@ -9,12 +8,10 @@ import { WorkflowDetail } from "../components/WorkflowDetail"; export const WorkflowDetailPage: React.FC = () => { return ( - - - - - + + + - + ); }; diff --git a/frontend/src/features/myWorkflows/pages/WorkflowsPage.tsx b/frontend/src/features/myWorkflows/pages/WorkflowsPage.tsx index 0c80e0f4..47fa01c1 100644 --- a/frontend/src/features/myWorkflows/pages/WorkflowsPage.tsx +++ b/frontend/src/features/myWorkflows/pages/WorkflowsPage.tsx @@ -1,6 +1,5 @@ import { Grid } from "@mui/material"; import { Breadcrumbs } from "components/Breadcrumbs"; -import PrivateLayout from "components/PrivateLayout"; import { WorkflowList } from "../components/WorkflowsList"; @@ -10,15 +9,13 @@ import { WorkflowList } from "../components/WorkflowsList"; export const WorkflowsPage: React.FC = () => { return ( - - - - - - - - + + + - + + + + ); }; diff --git a/frontend/src/features/myWorkflows/routes/index.tsx b/frontend/src/features/myWorkflows/routes/index.tsx new file mode 100644 index 00000000..c3cb86d6 --- /dev/null +++ b/frontend/src/features/myWorkflows/routes/index.tsx @@ -0,0 +1,38 @@ +import { AuthorizationRoute, PrivateRoute } from "@components/Routes"; +import React from "react"; +import { Route, Routes } from "react-router-dom"; + +import { ResultsReportPage, WorkflowDetailPage, WorkflowsPage } from "../pages"; + +export const MyWorkflowsRoutes: React.FC = () => { + return ( + + }> + + + + } + /> + + + + } + /> + + + + } + /> + + + ); +}; diff --git a/frontend/src/features/myWorkflows/types/runs.ts b/frontend/src/features/myWorkflows/types/runs.ts index 3b460740..9651c1e1 100644 --- a/frontend/src/features/myWorkflows/types/runs.ts +++ b/frontend/src/features/myWorkflows/types/runs.ts @@ -1,10 +1,3 @@ -interface IPaginationMetadata { - page: number; - last_page: number; - records: number; - total: number; -} - enum runState { success = "success", failed = "failed", @@ -52,10 +45,5 @@ export interface IWorkflowRunTasks { export interface IGetWorkflowRunsResponseInterface { data?: IWorkflowRuns[]; - metadata?: IPaginationMetadata; -} - -export interface IGetWorkflowRunTasksResponseInterface { - data?: IWorkflowRunTasks[]; - metadata?: IPaginationMetadata; + metadata?: PaginationMetadata; } diff --git a/frontend/src/features/myWorkflows/types/workflow.ts b/frontend/src/features/myWorkflows/types/workflow.ts index e9d65967..b43a7f9b 100644 --- a/frontend/src/features/myWorkflows/types/workflow.ts +++ b/frontend/src/features/myWorkflows/types/workflow.ts @@ -47,7 +47,7 @@ export interface IWorkflowSchema { } export interface IWorkDominoSchema { - nodes: Record; + nodes: Record; edges: any[]; } diff --git a/frontend/src/features/workflowEditor/api/index.ts b/frontend/src/features/workflowEditor/api/index.ts new file mode 100644 index 00000000..88f8e754 --- /dev/null +++ b/frontend/src/features/workflowEditor/api/index.ts @@ -0,0 +1,2 @@ +export * from "./workflow"; +export * from "./workflowsExample"; diff --git a/frontend/src/features/workflowEditor/api/workflow/index.ts b/frontend/src/features/workflowEditor/api/workflow/index.ts new file mode 100644 index 00000000..e23dce9b --- /dev/null +++ b/frontend/src/features/workflowEditor/api/workflow/index.ts @@ -0,0 +1 @@ +export * from "./useCreateWorkflow"; diff --git a/frontend/src/features/workflowEditor/api/workflow/useCreateWorkflow.ts b/frontend/src/features/workflowEditor/api/workflow/useCreateWorkflow.ts new file mode 100644 index 00000000..42d3da44 --- /dev/null +++ b/frontend/src/features/workflowEditor/api/workflow/useCreateWorkflow.ts @@ -0,0 +1,43 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { type IPostWorkflowResponseInterface } from "features/myWorkflows/types"; +import { type CreateWorkflowRequest } from "features/workflowEditor/context/types"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface UsePostWorkflow { + workspaceId?: string; +} + +export const useCreateWorkflow = ( + { workspaceId }: UsePostWorkflow, + config: MutationConfig< + CreateWorkflowRequest, + IPostWorkflowResponseInterface + > = {}, +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (params) => { + if (!workspaceId) throw new Error("No workspace selected"); + return await postWorkflow({ ...params, workspaceId }); + }, + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: ["WORKFLOWS", workspaceId], + }); + }, + ...config, + }); +}; + +const postWorkflow = async ({ + workspaceId, + ...payload +}: CreateWorkflowRequest & + UsePostWorkflow): Promise => { + return await dominoApiClient.post( + `/workspaces/${workspaceId}/workflows`, + payload, + ); +}; diff --git a/frontend/src/features/workflowEditor/api/workflowsExample/getWorkflowExamples.ts b/frontend/src/features/workflowEditor/api/workflowsExample/getWorkflowExamples.ts index e4f50d97..018e5118 100644 --- a/frontend/src/features/workflowEditor/api/workflowsExample/getWorkflowExamples.ts +++ b/frontend/src/features/workflowEditor/api/workflowsExample/getWorkflowExamples.ts @@ -1,19 +1,8 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { useQuery, skipToken } from "@tanstack/react-query"; import axios from "axios"; import { type WorkflowPieceData } from "features/workflowEditor/context/types"; import { type Edge, type Node } from "reactflow"; -import useSWR from "swr"; - -const REPO_URL = - "https://raw.githubusercontent.com/Tauffer-Consulting/domino_pieces_gallery/main/workflows_gallery"; - -const getWorkflowsExampleUrl = `${REPO_URL}/index.json`; - -type GithubReposContent = Array<{ - title: string; - description: string; - jsonFile: string; - levelTag: "Advanced" | "Beginner" | "Intermediate"; -}>; interface JSONFile { workflowPieces: Record; @@ -29,6 +18,29 @@ export type WorkflowsGalleryExamples = Array<{ levelTag: "Advanced" | "Beginner" | "Intermediate"; }>; +export const useWorkflowsExamples = ( + fetch: boolean, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: ["WORKFLOWS-EXAMPLES"], + queryFn: fetch ? async () => await getWorkflowsExample() : skipToken, + ...config, + }); +}; + +const REPO_URL = + "https://raw.githubusercontent.com/Tauffer-Consulting/domino_pieces_gallery/main/workflows_gallery"; + +const getWorkflowsExampleUrl = `${REPO_URL}/index.json`; + +type GithubReposContent = Array<{ + title: string; + description: string; + jsonFile: string; + levelTag: "Advanced" | "Beginner" | "Intermediate"; +}>; + const getWorkflowsExample: () => Promise = async () => { const { data } = await axios.get( @@ -44,16 +56,3 @@ const getWorkflowsExample: () => Promise = return jsons; }; - -export const useAuthenticatedGetWorkflowsExamples = (fetch: boolean) => { - const fetcher = async () => await getWorkflowsExample().then((data) => data); - - return useSWR( - fetch ? getWorkflowsExampleUrl : null, - async () => await fetcher(), - { - revalidateOnFocus: false, - revalidateOnReconnect: false, - }, - ); -}; diff --git a/frontend/src/features/workflowEditor/components/ButtonsMenu/index.tsx b/frontend/src/features/workflowEditor/components/ButtonsMenu/index.tsx index 31df0d85..ea3b76c4 100644 --- a/frontend/src/features/workflowEditor/components/ButtonsMenu/index.tsx +++ b/frontend/src/features/workflowEditor/components/ButtonsMenu/index.tsx @@ -103,7 +103,7 @@ export const ButtonsMenu: React.FC = ({ if (e instanceof yup.ValidationError) { toast.error("This JSON file is incompatible or corrupted"); } else { - console.log(e); + console.error(e); } } if (fileInputRef.current) { diff --git a/frontend/src/features/workflowEditor/components/Modals/DifferencesModal.tsx b/frontend/src/features/workflowEditor/components/Modals/DifferencesModal.tsx index d24c2fa4..a9ef6685 100644 --- a/frontend/src/features/workflowEditor/components/Modals/DifferencesModal.tsx +++ b/frontend/src/features/workflowEditor/components/Modals/DifferencesModal.tsx @@ -86,7 +86,7 @@ export const DifferencesModal = forwardRef( {!!installedPieces.length && ( <> Incorrect version pieces need to be manually update on - workspace settings, + workspace settings, )} diff --git a/frontend/src/features/workflowEditor/components/Modals/MyWorkflowsGalleryModal.tsx b/frontend/src/features/workflowEditor/components/Modals/MyWorkflowsGalleryModal.tsx index 37206e43..0e2e8b54 100644 --- a/frontend/src/features/workflowEditor/components/Modals/MyWorkflowsGalleryModal.tsx +++ b/frontend/src/features/workflowEditor/components/Modals/MyWorkflowsGalleryModal.tsx @@ -1,3 +1,4 @@ +import { useWorkspaces } from "@context/workspaces"; import CheckCircleIcon from "@mui/icons-material/CheckCircle"; import { Card, @@ -11,10 +12,7 @@ import { import Pagination from "@mui/material/Pagination"; import Stack from "@mui/material/Stack"; import { Modal, type ModalRef } from "components/Modal"; -import { - useAuthenticatedGetWorkflowId, - useAuthenticatedGetWorkflows, -} from "features/myWorkflows"; +import { useWorkflow, useWorkflows } from "features/myWorkflows"; import { type IWorkflow } from "features/myWorkflows/types"; import theme from "providers/theme.config"; import { forwardRef, type ForwardedRef, useState, useMemo } from "react"; @@ -32,11 +30,17 @@ const MyWorkflowExamplesGalleryModal = forwardRef( ) => { const [page, setPage] = useState(0); const [selected, setSelected] = useState(null); + const { workspace } = useWorkspaces(); - const { data: workflows } = useAuthenticatedGetWorkflows(page, 9); + const { data: workflows } = useWorkflows({ + page, + pageSize: 9, + workspaceId: workspace?.id, + }); - const { data: workflow } = useAuthenticatedGetWorkflowId({ - id: selected !== null ? String(selected) : undefined, + const { data: workflow } = useWorkflow({ + workflowId: selected !== null ? String(selected) : undefined, + workspaceId: workspace?.id, }); const cardsContents = useMemo( diff --git a/frontend/src/features/workflowEditor/components/Modals/WorkflowExamplesGalleryModal.tsx b/frontend/src/features/workflowEditor/components/Modals/WorkflowExamplesGalleryModal.tsx index 2ab617bc..796d4017 100644 --- a/frontend/src/features/workflowEditor/components/Modals/WorkflowExamplesGalleryModal.tsx +++ b/frontend/src/features/workflowEditor/components/Modals/WorkflowExamplesGalleryModal.tsx @@ -10,7 +10,7 @@ import { import { Modal, type ModalRef } from "components/Modal"; import { type WorkflowsGalleryExamples, - useAuthenticatedGetWorkflowsExamples, + useWorkflowsExamples, } from "features/workflowEditor/api/workflowsExample"; import theme from "providers/theme.config"; import { forwardRef, type ForwardedRef, useState, useMemo } from "react"; @@ -88,7 +88,7 @@ const WorkflowExamplesGalleryModal = forwardRef( ) => { const [selected, setSelected] = useState(null); // only make requests if USE_LOCAL_CARDS=false - const { data } = useAuthenticatedGetWorkflowsExamples(!USE_LOCAL_CARDS); + const { data } = useWorkflowsExamples(!USE_LOCAL_CARDS); const cardsContents = useMemo(() => { if (USE_LOCAL_CARDS) { diff --git a/frontend/src/features/workflowEditor/components/WorkflowEditor/index.tsx b/frontend/src/features/workflowEditor/components/WorkflowEditor/index.tsx index 3ce6ee4d..8be16c7a 100644 --- a/frontend/src/features/workflowEditor/components/WorkflowEditor/index.tsx +++ b/frontend/src/features/workflowEditor/components/WorkflowEditor/index.tsx @@ -84,8 +84,6 @@ export const WorkflowsEditorComponent: React.FC = () => { }, {}), ) as any; - console.log("validationSchema", validationSchema); - const resolver = yupResolver(validationSchema); const validatedData = await resolver(payload.workflowPiecesData); @@ -129,16 +127,16 @@ export const WorkflowsEditorComponent: React.FC = () => { const data = generateWorkflowsEditorBodyParams(payload); - await handleCreateWorkflow({ workspace_id: workspace?.id, ...data }); + await handleCreateWorkflow({ ...data }); toast.success("Workflow created successfully."); setBackdropIsOpen(false); } catch (err) { setBackdropIsOpen(false); if (err instanceof AxiosError) { - console.log(err); + console.error(err); } else if (err instanceof Error) { - console.log(err); + console.error(err); toast.error( "Error while creating workflow, check your workflow settings and tasks.", ); diff --git a/frontend/src/features/workflowEditor/context/workflowsEditor.tsx b/frontend/src/features/workflowEditor/context/workflowsEditor.tsx index a55d54f7..42b9a52f 100644 --- a/frontend/src/features/workflowEditor/context/workflowsEditor.tsx +++ b/frontend/src/features/workflowEditor/context/workflowsEditor.tsx @@ -1,12 +1,9 @@ import { useWorkspaces } from "context/workspaces"; -import { - type IPostWorkflowParams, - useAuthenticatedPostWorkflow, -} from "features/myWorkflows/api"; import { type IWorkflowElement, type IPostWorkflowResponseInterface, } from "features/myWorkflows/types"; +import { useCreateWorkflow } from "features/workflowEditor/api"; import React, { type FC, useCallback } from "react"; import { type Edge } from "reactflow"; import { createCustomContext, generateTaskName } from "utils"; @@ -43,7 +40,7 @@ interface IWorkflowsEditorContext p: GenerateWorkflowsParams, ) => CreateWorkflowRequest; handleCreateWorkflow: ( - params: IPostWorkflowParams, + params: CreateWorkflowRequest, ) => Promise; clearStorageData: () => void; } @@ -55,7 +52,9 @@ const WorkflowsEditorProvider: FC<{ children?: React.ReactNode }> = ({ children, }) => { const { workspace } = useWorkspaces(); - const postWorkflow = useAuthenticatedPostWorkflow(); + const { mutateAsync: postWorkflow } = useCreateWorkflow({ + workspaceId: workspace?.id, + }); const { setWorkflowEdges, @@ -286,10 +285,9 @@ const WorkflowsEditorProvider: FC<{ children?: React.ReactNode }> = ({ ); const handleCreateWorkflow = useCallback( - async (payload: IPostWorkflowParams) => { + async (payload: CreateWorkflowRequest) => { return await postWorkflow({ ...payload, - workspace_id: workspace?.id ?? "", }); }, [postWorkflow, workspace], diff --git a/frontend/src/features/workflowEditor/index.ts b/frontend/src/features/workflowEditor/index.ts new file mode 100644 index 00000000..793a09b8 --- /dev/null +++ b/frontend/src/features/workflowEditor/index.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./routes"; diff --git a/frontend/src/features/workflowEditor/pages/workflowEditorPage.tsx b/frontend/src/features/workflowEditor/pages/workflowEditorPage.tsx index 6e987c9f..7983fb9d 100644 --- a/frontend/src/features/workflowEditor/pages/workflowEditorPage.tsx +++ b/frontend/src/features/workflowEditor/pages/workflowEditorPage.tsx @@ -1,22 +1,16 @@ import { Grid } from "@mui/material"; -import PrivateLayout from "components/PrivateLayout"; import { WorkflowsEditorComponent } from "../components/WorkflowEditor"; import WorkflowsEditorProviderWrapper from "../context"; -/** - * Workflows editor page - */ export const WorkflowsEditorPage: React.FC = () => { return ( - - - - - - - + + + + + - + ); }; diff --git a/frontend/src/features/workflowEditor/routes/index.tsx b/frontend/src/features/workflowEditor/routes/index.tsx new file mode 100644 index 00000000..b87b9e93 --- /dev/null +++ b/frontend/src/features/workflowEditor/routes/index.tsx @@ -0,0 +1,22 @@ +import { AuthorizationRoute, PrivateRoute } from "@components/Routes"; +import React from "react"; +import { Route, Routes } from "react-router-dom"; + +import { WorkflowsEditorPage } from "../pages"; + +export const WorkflowEditorRoute: React.FC = () => { + return ( + + }> + + + + } + /> + + + ); +}; diff --git a/frontend/src/features/workspaces/api/index.ts b/frontend/src/features/workspaces/api/index.ts new file mode 100644 index 00000000..1d55a11a --- /dev/null +++ b/frontend/src/features/workspaces/api/index.ts @@ -0,0 +1,3 @@ +export * from "./piece"; +export * from "./repository"; +export * from "./workspace"; diff --git a/frontend/src/features/workspaces/api/piece/index.ts b/frontend/src/features/workspaces/api/piece/index.ts new file mode 100644 index 00000000..741ede18 --- /dev/null +++ b/frontend/src/features/workspaces/api/piece/index.ts @@ -0,0 +1 @@ +export * from "./usePieces"; diff --git a/frontend/src/features/workspaces/api/piece/usePieces.ts b/frontend/src/features/workspaces/api/piece/usePieces.ts new file mode 100644 index 00000000..f34536e3 --- /dev/null +++ b/frontend/src/features/workspaces/api/piece/usePieces.ts @@ -0,0 +1,32 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { useQueries } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface GetRepoPiecesParams { + repositoryIds?: string[]; +} + +export const usePieces = ( + { repositoryIds }: GetRepoPiecesParams, + config: QueryConfig = {}, +) => { + return useQueries({ + queries: + repositoryIds?.map((repositoryId) => ({ + queryKey: ["PIECES", repositoryId], + queryFn: async () => await getPieces(repositoryId), + })) ?? [], + combine: (results) => { + return { + data: results + .flatMap((result) => result.data) + .filter((data) => data !== undefined) as unknown as Piece[], + pending: results.some((result) => result.isPending), + }; + }, + ...config, + }); +}; + +const getPieces = async (repositoryId: string): Promise => + await dominoApiClient.get(`pieces-repositories/${repositoryId}/pieces`); diff --git a/frontend/src/features/workspaces/api/repository/index.ts b/frontend/src/features/workspaces/api/repository/index.ts new file mode 100644 index 00000000..6af804e4 --- /dev/null +++ b/frontend/src/features/workspaces/api/repository/index.ts @@ -0,0 +1,6 @@ +export * from "./useAddRepository"; +export * from "./useDeleteRepository"; +export * from "./useRepositories"; +export * from "./useRepositoriesReleases"; +export * from "./useRepositorySecrets"; +export * from "./useUpdateRepositorySecret"; diff --git a/frontend/src/features/workspaces/api/repository/useAddRepository.ts b/frontend/src/features/workspaces/api/repository/useAddRepository.ts new file mode 100644 index 00000000..2adc633d --- /dev/null +++ b/frontend/src/features/workspaces/api/repository/useAddRepository.ts @@ -0,0 +1,50 @@ +import { type repositorySource } from "@context/workspaces/types"; +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +export interface AddRepositoryParams { + source: repositorySource | string; + path: string; + version: string; + url: string; +} + +export interface AddRepositoryResponse { + id: number; + name: string; + created_at: string; + source: repositorySource | string; + label: string; + path: string; + version: string; + workspace_id: number; +} + +interface UseAddRepository { + workspaceId?: string; +} + +export const useAddRepository = ( + { workspaceId }: UseAddRepository, + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async (params) => { + if (!workspaceId) { + throw new Error("No workspace selected"); + } + return await postPiecesRepository({ + workspace_id: workspaceId, + ...params, + }); + }, + ...config, + }); +}; + +const postPiecesRepository = async ( + params: AddRepositoryParams & { workspace_id: string }, +): Promise => { + return await dominoApiClient.post("/pieces-repositories", params); +}; diff --git a/frontend/src/features/workspaces/api/repository/useDeleteRepository.ts b/frontend/src/features/workspaces/api/repository/useDeleteRepository.ts new file mode 100644 index 00000000..aea00b2c --- /dev/null +++ b/frontend/src/features/workspaces/api/repository/useDeleteRepository.ts @@ -0,0 +1,19 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +export const useDeleteRepository = ( + config: MutationConfig<{ id: string }> = {}, +) => { + return useMutation({ + mutationFn: async ({ id }) => { + await deleteRepository(id); + }, + + ...config, + }); +}; + +const deleteRepository: (id: string) => Promise = async (id) => { + await dominoApiClient.delete(`/pieces-repositories/${id}`); +}; diff --git a/frontend/src/features/workspaces/api/repository/useRepositories.ts b/frontend/src/features/workspaces/api/repository/useRepositories.ts new file mode 100644 index 00000000..00feced0 --- /dev/null +++ b/frontend/src/features/workspaces/api/repository/useRepositories.ts @@ -0,0 +1,54 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { skipToken, useQuery } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface PiecesRepositoriesParams { + page?: number; + page_size?: number; + name__like?: string; + path__like?: string; + version?: string; + source?: "github" | "default"; +} + +interface PiecesRepositories { + data: Repository[]; + metadata: PaginationMetadata; +} + +export const useRepositories = ( + { + workspaceId, + ...filters + }: PiecesRepositoriesParams & { workspaceId?: string }, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: ["REPOSITORIES", workspaceId, filters], + queryFn: workspaceId + ? async () => await getPiecesRepositories(filters, workspaceId) + : skipToken, + ...config, + }); +}; + +const getPiecesRepositories = async ( + { page = 0, page_size = 100, ...filters }: PiecesRepositoriesParams, + workspace: string, +): Promise => { + return await dominoApiClient.get( + getPiecesRepositoriesUrl({ page, page_size, ...filters }, workspace), + ); +}; + +const getPiecesRepositoriesUrl = ( + filters: PiecesRepositoriesParams, + workspace: string, +) => { + const query = new URLSearchParams(); + query.set("workspace_id", workspace); + for (const [key, value] of Object.entries(filters)) { + query.set(key, value); + } + return `/pieces-repositories?${query.toString()}`; +}; diff --git a/frontend/src/features/workspaces/api/repository/useRepositoriesReleases.ts b/frontend/src/features/workspaces/api/repository/useRepositoriesReleases.ts new file mode 100644 index 00000000..ac398a3f --- /dev/null +++ b/frontend/src/features/workspaces/api/repository/useRepositoriesReleases.ts @@ -0,0 +1,58 @@ +import { type repositorySource } from "@context/workspaces/types"; +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +export interface RepositoriesReleasesParams { + source: repositorySource; + path: string; +} + +export interface RepositoriesReleasesResponse { + version: string; + last_modified: string; +} + +interface UseRepositoriesReleases { + workspaceId?: string; +} + +export const useRepositoriesReleases = ( + { workspaceId }: UseRepositoriesReleases, + config: MutationConfig< + RepositoriesReleasesParams, + RepositoriesReleasesResponse[] + > = {}, +) => { + return useMutation({ + mutationFn: async ({ source, path }) => { + if (!workspaceId) { + throw new Error("No workspace selected"); + } + + return await getPiecesRepositoriesReleases({ + path, + source, + workspaceId, + }); + }, + ...config, + }); +}; + +const getPiecesRepositoriesReleases = async ({ + source, + path, + workspaceId, +}: RepositoriesReleasesParams & { workspaceId: string }): Promise< + RepositoriesReleasesResponse[] +> => { + const search = new URLSearchParams(); + search.set("source", source); + search.set("path", path); + search.set("workspace_id", workspaceId); + + return await dominoApiClient.get( + `/pieces-repositories/releases?${search.toString()}`, + ); +}; diff --git a/frontend/src/features/workspaces/api/repository/useRepositorySecrets.ts b/frontend/src/features/workspaces/api/repository/useRepositorySecrets.ts new file mode 100644 index 00000000..906c2d13 --- /dev/null +++ b/frontend/src/features/workspaces/api/repository/useRepositorySecrets.ts @@ -0,0 +1,34 @@ +import { type QueryConfig } from "@services/clients/react-query.client"; +import { skipToken, useQuery } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface RepositorySecretsParams { + repositoryId: string; +} + +interface RepositorySecrets { + id: number; + name: string; + is_filled: boolean; +} + +export const useRepositorySecrets = ( + { repositoryId }: Partial, + config: QueryConfig = {}, +) => { + return useQuery({ + queryKey: ["REPOSITORIES-SECRETS", repositoryId], + queryFn: repositoryId + ? async () => await getRepositorySecrets(repositoryId) + : skipToken, + ...config, + }); +}; + +const getRepositorySecrets = async ( + repositoryId: string, +): Promise => { + return await dominoApiClient.get( + `/pieces-repositories/${repositoryId}/secrets`, + ); +}; diff --git a/frontend/src/features/workspaces/api/repository/useUpdateRepositorySecret.ts b/frontend/src/features/workspaces/api/repository/useUpdateRepositorySecret.ts new file mode 100644 index 00000000..e726460e --- /dev/null +++ b/frontend/src/features/workspaces/api/repository/useUpdateRepositorySecret.ts @@ -0,0 +1,39 @@ +// TODO move to /runs +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface PatchRepositorySecretParams { + repositoryId: string; + secretId: string; + payload: { + value: string | null; + }; +} + +export const useUpdateRepositorySecret = ( + config: MutationConfig = {}, +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (params: PatchRepositorySecretParams) => { + await patchRepositorySecret(params); + }, + onSuccess: async (_, { repositoryId }) => { + await queryClient.invalidateQueries({ + queryKey: ["REPOSITORIES-SECRETS", repositoryId], + }); + }, + ...config, + }); +}; + +const patchRepositorySecret: ( + params: PatchRepositorySecretParams, +) => Promise = async ({ payload, repositoryId, secretId }) => { + await dominoApiClient.patch( + `/pieces-repositories/${repositoryId}/secrets/${secretId}`, + payload, + ); +}; diff --git a/frontend/src/features/workspaces/api/workspace/index.ts b/frontend/src/features/workspaces/api/workspace/index.ts new file mode 100644 index 00000000..ead8cadb --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/index.ts @@ -0,0 +1,9 @@ +export * from "./useAcceptWorkspaceInvite"; +export * from "./useCreateWorkspace"; +export * from "./useDeleteWorkspace"; +export * from "./useGetWorkspaces"; +export * from "./useInviteWorkspace"; +export * from "./useRejectWorkspaceInvite"; +export * from "./useRemoveUserFomWorkspace"; +export * from "./useUpdateWorkspace"; +export * from "./useWorkspaceUsers"; diff --git a/frontend/src/features/workspaces/api/workspace/useAcceptWorkspaceInvite.ts b/frontend/src/features/workspaces/api/workspace/useAcceptWorkspaceInvite.ts new file mode 100644 index 00000000..30504b75 --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useAcceptWorkspaceInvite.ts @@ -0,0 +1,24 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface AcceptWorkspaceInviteParams { + workspaceId: string; +} + +export const useAcceptWorkspaceInvite = ( + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async (params) => { + await acceptWorkspaceInvite(params); + }, + ...config, + }); +}; + +const acceptWorkspaceInvite = async ({ + workspaceId, +}: AcceptWorkspaceInviteParams): Promise => { + await dominoApiClient.post(`/workspaces/${workspaceId}/invites/accept`, null); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useCreateWorkspace.ts b/frontend/src/features/workspaces/api/workspace/useCreateWorkspace.ts new file mode 100644 index 00000000..911d03ce --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useCreateWorkspace.ts @@ -0,0 +1,24 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +type CreateWorkspaceResponse = Record; + +export interface CreateWorkspaceParams { + name: string; +} + +export const useCreateWorkspace = ( + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async (params) => await postWorkspaces(params), + ...config, + }); +}; + +const postWorkspaces: ( + params: CreateWorkspaceParams, +) => Promise = async (params) => { + return await dominoApiClient.post(`/workspaces`, params); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useDeleteWorkspace.ts b/frontend/src/features/workspaces/api/workspace/useDeleteWorkspace.ts new file mode 100644 index 00000000..ffcf5ac4 --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useDeleteWorkspace.ts @@ -0,0 +1,24 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +export interface DeleteWorkspaceParams { + workspaceId: string; +} + +export const useDeleteWorkspace = ( + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async ({ workspaceId }) => { + await deleteWorkspace({ workspaceId }); + }, + ...config, + }); +}; + +const deleteWorkspace = async ({ + workspaceId, +}: DeleteWorkspaceParams): Promise => { + await dominoApiClient.delete(`/workspaces/${workspaceId}`); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useGetWorkspaces.ts b/frontend/src/features/workspaces/api/workspace/useGetWorkspaces.ts new file mode 100644 index 00000000..2f595b1c --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useGetWorkspaces.ts @@ -0,0 +1,14 @@ +import { type WorkspaceSummary } from "@context/workspaces/types"; +import { useQuery } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +const getWorkspaces: () => Promise = async () => { + return await dominoApiClient.get("/workspaces"); +}; + +export const useGetWorkspaces = () => { + return useQuery({ + queryKey: [`WORKSPACES`], + queryFn: async () => await getWorkspaces(), + }); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useInviteWorkspace.ts b/frontend/src/features/workspaces/api/workspace/useInviteWorkspace.ts new file mode 100644 index 00000000..ce2f73ed --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useInviteWorkspace.ts @@ -0,0 +1,34 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface InviteWorkspaceParams { + userEmail: string; + permission: string; +} + +interface UseWorkspaceInvite { + workspaceId?: string; +} + +export const useInviteWorkspace = ( + { workspaceId }: UseWorkspaceInvite, + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async ({ permission, userEmail }) => { + if (!workspaceId) throw new Error("No workspace selected"); + await inviteWorkspace({ workspaceId, permission, userEmail }); + }, + ...config, + }); +}; + +const inviteWorkspace = async ( + params: InviteWorkspaceParams & UseWorkspaceInvite, +): Promise => { + await dominoApiClient.post(`/workspaces/${params.workspaceId}/invites`, { + user_email: params.userEmail, + permission: params.permission, + }); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useRejectWorkspaceInvite.ts b/frontend/src/features/workspaces/api/workspace/useRejectWorkspaceInvite.ts new file mode 100644 index 00000000..fac68718 --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useRejectWorkspaceInvite.ts @@ -0,0 +1,24 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface RejectWorkspaceInviteParams { + workspaceId: string; +} + +export const useRejectWorkspaceInvite = ( + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async (params) => { + await rejectWorkspaceInvite(params); + }, + ...config, + }); +}; + +const rejectWorkspaceInvite: ( + params: RejectWorkspaceInviteParams, +) => Promise = async ({ workspaceId }) => { + await dominoApiClient.post(`/workspaces/${workspaceId}/invites/reject`, null); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useRemoveUserFomWorkspace.ts b/frontend/src/features/workspaces/api/workspace/useRemoveUserFomWorkspace.ts new file mode 100644 index 00000000..9f504d79 --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useRemoveUserFomWorkspace.ts @@ -0,0 +1,30 @@ +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface RemoveUserWorkspaceParams { + userId: string; +} + +interface UseRemoveUserFomWorkspace { + workspaceId?: string; +} + +export const useRemoveUserFomWorkspace = ( + { workspaceId }: UseRemoveUserFomWorkspace, + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async ({ userId }) => { + if (!workspaceId) throw new Error("No workspace selected"); + await removeUserFomWorkspace({ userId, workspaceId }); + }, + ...config, + }); +}; + +const removeUserFomWorkspace: ( + params: RemoveUserWorkspaceParams & UseRemoveUserFomWorkspace, +) => Promise = async ({ userId, workspaceId }) => { + await dominoApiClient.delete(`/workspaces/${workspaceId}/users/${userId}`); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useUpdateWorkspace.ts b/frontend/src/features/workspaces/api/workspace/useUpdateWorkspace.ts new file mode 100644 index 00000000..4bcba6b3 --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useUpdateWorkspace.ts @@ -0,0 +1,35 @@ +// TODO move to /runs +import { type WorkspaceSummary } from "@context/workspaces/types"; +import { type MutationConfig } from "@services/clients/react-query.client"; +import { useMutation } from "@tanstack/react-query"; +import { dominoApiClient } from "services/clients/domino.client"; + +interface PatchWorkspaceParams { + name?: string | null; + github_access_token?: string | null; +} + +interface UseUpdateWorkspace { + workspaceId?: string; +} + +export const useUpdateWorkspace = ( + { workspaceId }: UseUpdateWorkspace, + config: MutationConfig = {}, +) => { + return useMutation({ + mutationFn: async (params) => { + if (!workspaceId) throw new Error("No workspace selected"); + + return await patchWorkspace({ workspaceId, ...params }); + }, + ...config, + }); +}; + +const patchWorkspace = async ({ + workspaceId, + ...params +}: PatchWorkspaceParams & UseUpdateWorkspace): Promise => { + return await dominoApiClient.patch(`/workspaces/${workspaceId}`, params); +}; diff --git a/frontend/src/features/workspaces/api/workspace/useWorkspaceUsers.ts b/frontend/src/features/workspaces/api/workspace/useWorkspaceUsers.ts new file mode 100644 index 00000000..9ce05c88 --- /dev/null +++ b/frontend/src/features/workspaces/api/workspace/useWorkspaceUsers.ts @@ -0,0 +1,70 @@ +import { type workspaceStatus } from "@context/workspaces/types"; +import { skipToken, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useEffect } from "react"; +import { dominoApiClient } from "services/clients/domino.client"; +import { type QueryConfig } from "services/clients/react-query.client"; + +interface GetWorkspaceUsersParams { + page: number; + pageSize: number; +} + +export interface GetWorkspaceUsersResponse { + data: Array<{ + user_id: number; + user_email: string; + user_permission: string; + status: workspaceStatus; + }>; + metadata: PaginationMetadata; +} + +type UseGetWorkspaceUsers = Partial & { + workspaceId?: string; +}; + +export const useWorkspaceUsers = ( + { page = 0, pageSize = 10, workspaceId }: UseGetWorkspaceUsers, + config: QueryConfig = {}, +) => { + const queryClient = useQueryClient(); + + const response = useQuery({ + queryKey: ["USERS", workspaceId, page, pageSize], + queryFn: workspaceId + ? async () => await getWorkspaceMembers({ page, pageSize, workspaceId }) + : skipToken, + ...config, + }); + + useEffect(() => { + if ( + response.data?.metadata.last_page && + response.data?.metadata.last_page > page + ) + void queryClient.prefetchQuery({ + queryKey: ["USERS", workspaceId, page + 1, pageSize], + queryFn: workspaceId + ? async () => + await getWorkspaceMembers({ + page: page + 1, + pageSize, + workspaceId, + }) + : skipToken, + }); + }, [response, page, pageSize, workspaceId]); + + return response; +}; + +const getWorkspaceMembers = async ({ + page, + pageSize, + workspaceId, +}: GetWorkspaceUsersParams & + UseGetWorkspaceUsers): Promise => { + return await dominoApiClient.get( + `/workspaces/${workspaceId}/users?page=${page}&page_size=${pageSize}`, + ); +}; diff --git a/frontend/src/features/workspaces/components/workspaceSettings/RepositoriesCard.tsx b/frontend/src/features/workspaces/components/workspaceSettings/RepositoriesCard.tsx index 062701df..725df902 100644 --- a/frontend/src/features/workspaces/components/workspaceSettings/RepositoriesCard.tsx +++ b/frontend/src/features/workspaces/components/workspaceSettings/RepositoriesCard.tsx @@ -30,7 +30,7 @@ import { import TextField from "@mui/material/TextField"; import { usesPieces } from "context/workspaces"; import { repositorySource } from "context/workspaces/types"; -import { type IPieceRepositoryMetadata } from "features/myWorkflows/api"; +import { type RepositoriesReleasesResponse } from "features/workspaces"; import { type FC, type ReactNode, useCallback, useMemo, useState } from "react"; import { toast } from "react-toastify"; @@ -47,14 +47,13 @@ export const RepositoriesCard: FC = () => { const [version, setVersion] = useState(""); const [selectedIndex, setSelectedIndex] = useState(null); const [availableVersions, setAvailableVersions] = useState< - IPieceRepositoryMetadata[] + RepositoriesReleasesResponse[] >([]); const { repositories, handleAddRepository, handleFetchRepoReleases, - handleRefreshRepositories, setSelectedRepositoryId, selectedRepositoryId, handleDeleteRepository, @@ -98,18 +97,10 @@ export const RepositoriesCard: FC = () => { }).finally(() => { setStep("FETCH_METADATA"); setAvailableVersions([]); - void handleRefreshRepositories(); setUrl(""); setIsStepLoading(false); }); - }, [ - handleAddRepository, - handleRefreshRepositories, - path, - source, - version, - url, - ]); + }, [handleAddRepository, path, source, version, url]); const handleNextStep = useCallback(() => { switch (step) { @@ -185,7 +176,7 @@ export const RepositoriesCard: FC = () => { (e: any) => { const repositoryId = e.currentTarget.value; if (repositoryId === selectedRepositoryId) { - setSelectedRepositoryId(null); + setSelectedRepositoryId(undefined); setSelectedIndex(null); } else { setSelectedRepositoryId(repositoryId || null); @@ -196,17 +187,11 @@ export const RepositoriesCard: FC = () => { ); const handleDeletePieceRepository = useCallback( - (e: React.SyntheticEvent) => { + async (e: React.SyntheticEvent) => { const repositoryId = e.currentTarget.value; - handleDeleteRepository(repositoryId) - .then(() => { - void handleRefreshRepositories(); - }) - .catch((error) => { - console.log(error); - }); + await handleDeleteRepository({ id: repositoryId }); }, - [handleDeleteRepository, handleRefreshRepositories], + [handleDeleteRepository], ); return ( diff --git a/frontend/src/features/workspaces/components/workspaceSettings/SecretsCard.tsx b/frontend/src/features/workspaces/components/workspaceSettings/SecretsCard.tsx index 15c84cbd..589dfed5 100644 --- a/frontend/src/features/workspaces/components/workspaceSettings/SecretsCard.tsx +++ b/frontend/src/features/workspaces/components/workspaceSettings/SecretsCard.tsx @@ -1,4 +1,8 @@ /* eslint-disable react/prop-types */ +import { + useRepositorySecrets, + useUpdateRepositorySecret, +} from "@features/workspaces/api"; import CancelIcon from "@mui/icons-material/Cancel"; import DeleteIcon from "@mui/icons-material/Delete"; import EditIcon from "@mui/icons-material/Edit"; @@ -14,10 +18,6 @@ import { IconButton, Tooltip, } from "@mui/material"; -import { - useAuthenticatedGetRepositorySecrets, - useAuthenticatedPatchRepositorySecret, -} from "features/myWorkflows/api"; import { useState, useImperativeHandle, @@ -30,7 +30,7 @@ import { useForm } from "react-hook-form"; import { toast } from "react-toastify"; interface SecretsCardProps { - repositoryId: number | null; + repositoryId?: number; } /* eslint-disable react/prop-types */ @@ -46,12 +46,11 @@ const SecretsCard = (props: SecretsCardProps, ref: Ref) => { ...ref, })); - const { data: secrets, mutate: refreshSecrets } = - useAuthenticatedGetRepositorySecrets({ - repositoryId: repositoryId?.toString() ?? "", - }); + const { data: secrets, refetch: refreshSecrets } = useRepositorySecrets({ + repositoryId: repositoryId?.toString() ?? "", + }); - const patchRepository = useAuthenticatedPatchRepositorySecret(); + const { mutateAsync: patchRepository } = useUpdateRepositorySecret(); const handleEditSecret = useCallback((e: any) => { e.preventDefault(); @@ -114,8 +113,7 @@ const SecretsCard = (props: SecretsCardProps, ref: Ref) => { setCurrrentEdittingSecretId(null); }) .catch((err) => { - console.log(err); - toast.error("Error while updating secret."); + console.error(err); }); }, [getValues, repositoryId, patchRepository, refreshSecrets, resetField], @@ -124,7 +122,7 @@ const SecretsCard = (props: SecretsCardProps, ref: Ref) => { const listItems = useMemo(() => { const auxListItems = secrets && secrets?.length > 0 ? ( - secrets?.map((secret, index) => ( + secrets.map((secret, index) => ( { } }, [storageRepository]); - const { data: secrets, mutate: refreshSecrets } = - useAuthenticatedGetRepositorySecrets({ - repositoryId: storageRepository?.id.toString() ?? "", - }); + const { data: secrets, refetch: refreshSecrets } = useRepositorySecrets({ + repositoryId: storageRepository?.id.toString() ?? "", + }); - const patchRepositorySecret = useAuthenticatedPatchRepositorySecret(); + const { mutateAsync: patchRepositorySecret } = useUpdateRepositorySecret(); const handleEditSecret = useCallback((e: any) => { e.preventDefault(); @@ -115,8 +114,7 @@ const StorageSecretsCard = () => { setCurrrentEdittingSecretId(null); }) .catch((err) => { - console.log(err); - toast.error("Error while updating secret."); + console.error(err); }); }, [ diff --git a/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceMembersCard.tsx b/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceMembersCard.tsx index 0850fb61..353a2467 100644 --- a/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceMembersCard.tsx +++ b/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceMembersCard.tsx @@ -30,7 +30,6 @@ const WorkspaceMembersCard = () => { workspaceUsersTablePageSize, setWorkspaceUsersTablePageSize, workspaceUsers, - workspaceUsersRefresh, } = useWorkspaces(); const [removeUserId, setRemoveUserId] = useState(""); @@ -123,13 +122,7 @@ const WorkspaceMembersCard = () => { } setIsOpenRemoveDialog(false); setRemoveUserId(null); - workspaceUsersRefresh(); - }, [ - workspace, - removeUserId, - handleRemoveUserWorkspace, - workspaceUsersRefresh, - ]); + }, [workspace, removeUserId, handleRemoveUserWorkspace]); return ( diff --git a/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceSecretsCard.tsx b/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceSecretsCard.tsx index 3b701d40..016f810a 100644 --- a/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceSecretsCard.tsx +++ b/frontend/src/features/workspaces/components/workspaceSettings/WorkspaceSecretsCard.tsx @@ -1,4 +1,5 @@ /* eslint-disable react/prop-types */ +import { useUpdateWorkspace } from "@features/workspaces/api"; import CancelIcon from "@mui/icons-material/Cancel"; import DeleteIcon from "@mui/icons-material/Delete"; import EditIcon from "@mui/icons-material/Edit"; @@ -15,7 +16,6 @@ import { IconButton, } from "@mui/material"; import { useWorkspaces } from "context/workspaces"; -import { useAuthenticatedPatchWorkspace } from "context/workspaces/api"; import { useState, useCallback, useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "react-toastify"; @@ -30,7 +30,9 @@ const WorkspaceSecretsCard = () => { const { handleUpdateWorkspace } = useWorkspaces(); const { workspace } = useWorkspaces(); - const patchWorkspace = useAuthenticatedPatchWorkspace(); + const { mutateAsync: patchWorkspace } = useUpdateWorkspace({ + workspaceId: workspace?.id, + }); useEffect(() => { if (workspace) { @@ -57,12 +59,11 @@ const WorkspaceSecretsCard = () => { github_access_token: null, }; patchWorkspace({ - workspaceId: workspace?.id, - payload, + ...payload, }) .then((response) => { toast.success("Secret updated."); - handleUpdateWorkspace(response?.data); + handleUpdateWorkspace(response); resetField(`github-token-workspace-${workspace?.id}`, { keepTouched: false, }); @@ -88,12 +89,11 @@ const WorkspaceSecretsCard = () => { github_access_token: formValue, }; patchWorkspace({ - workspaceId: workspace?.id, - payload, + ...payload, }) .then((response) => { toast.success("Secret updated."); - handleUpdateWorkspace(response?.data); + handleUpdateWorkspace(response); }) .catch((_err) => { toast.error("Error while updating secrets"); diff --git a/frontend/src/features/workspaces/components/workspaceSettings/index.tsx b/frontend/src/features/workspaces/components/workspaceSettings/index.tsx index 8e7d776f..c72590f3 100644 --- a/frontend/src/features/workspaces/components/workspaceSettings/index.tsx +++ b/frontend/src/features/workspaces/components/workspaceSettings/index.tsx @@ -3,7 +3,6 @@ import TabList from "@mui/lab/TabList"; import TabPanel from "@mui/lab/TabPanel"; import { Box, Grid, Typography } from "@mui/material"; import Tab from "@mui/material/Tab"; -import PrivateLayout from "components/PrivateLayout"; import { useWorkspaces, usesPieces } from "context/workspaces"; import { useState } from "react"; @@ -21,7 +20,7 @@ const WorkspaceSettingsComponent = () => { const [value, setValue] = useState("1"); return ( - + <> { - + ); }; diff --git a/frontend/src/features/workspaces/components/workspaces/WorkspaceListItem.tsx b/frontend/src/features/workspaces/components/workspaces/WorkspaceListItem.tsx index 6c7d641b..0f39374c 100644 --- a/frontend/src/features/workspaces/components/workspaces/WorkspaceListItem.tsx +++ b/frontend/src/features/workspaces/components/workspaces/WorkspaceListItem.tsx @@ -16,13 +16,13 @@ import { Tooltip, Chip, } from "@mui/material"; -import { type IWorkspaceSummary } from "context/workspaces/types"; +import { type WorkspaceSummary } from "context/workspaces/types"; import theme from "providers/theme.config"; import { type FC } from "react"; import { useNavigate } from "react-router-dom"; export const WorkspaceListItem: FC<{ - workspace: IWorkspaceSummary; + workspace: WorkspaceSummary; handleSelect: () => void; handleDelete: () => void; handleLeave: () => void; @@ -145,7 +145,7 @@ export const WorkspaceListItem: FC<{ sx={{ minWidth: "auto" }} onClick={() => { handleSelect(); - navigate("/workspace-settings"); + navigate("/workspaces/settings"); }} > diff --git a/frontend/src/features/workspaces/components/workspaces/WorkspacePendingListItem.tsx b/frontend/src/features/workspaces/components/workspaces/WorkspacePendingListItem.tsx index 9ae98b5b..e44518e1 100644 --- a/frontend/src/features/workspaces/components/workspaces/WorkspacePendingListItem.tsx +++ b/frontend/src/features/workspaces/components/workspaces/WorkspacePendingListItem.tsx @@ -9,11 +9,11 @@ import { Grid, } from "@mui/material"; import { useWorkspaces } from "context/workspaces"; -import { type IWorkspaceSummary } from "context/workspaces/types"; +import { type WorkspaceSummary } from "context/workspaces/types"; import { type FC } from "react"; export const WorkspacePendingListItem: FC<{ - workspace: IWorkspaceSummary; + workspace: WorkspaceSummary; selectedWorkspaceId: string | undefined; }> = ({ workspace }) => { const { handleAcceptWorkspaceInvite, handleRejectWorkspaceInvite } = diff --git a/frontend/src/features/workspaces/components/workspaces/index.tsx b/frontend/src/features/workspaces/components/workspaces/index.tsx index 7f09ddb4..b7d1da3f 100644 --- a/frontend/src/features/workspaces/components/workspaces/index.tsx +++ b/frontend/src/features/workspaces/components/workspaces/index.tsx @@ -9,7 +9,6 @@ import { DialogTitle, Button, } from "@mui/material"; -import PrivateLayout from "components/PrivateLayout"; import { useAuthentication } from "context/authentication"; import { useWorkspaces } from "context/workspaces"; import { type FC, useCallback, useState } from "react"; @@ -62,7 +61,7 @@ const WorkspacesComponent: FC = () => { }, [leaveWorkspaceId, handleRemoveUserWorkspace, auth.store.userId]); return ( - + <> { @@ -128,7 +127,7 @@ const WorkspacesComponent: FC = () => { - + My workspaces {workspacesError && ( @@ -175,7 +174,7 @@ const WorkspacesComponent: FC = () => { ), )} - + ); }; diff --git a/frontend/src/features/workspaces/index.ts b/frontend/src/features/workspaces/index.ts new file mode 100644 index 00000000..793a09b8 --- /dev/null +++ b/frontend/src/features/workspaces/index.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./routes"; diff --git a/frontend/src/features/workspaces/routes/index.tsx b/frontend/src/features/workspaces/routes/index.tsx new file mode 100644 index 00000000..e5d915ed --- /dev/null +++ b/frontend/src/features/workspaces/routes/index.tsx @@ -0,0 +1,23 @@ +import { AuthorizationRoute, PrivateRoute } from "@components/Routes"; +import React from "react"; +import { Route, Routes } from "react-router-dom"; + +import { WorkspaceSettingsPage, WorkspacesPage } from "../pages"; + +export const WorkspaceRoute: React.FC = () => { + return ( + + }> + } /> + + + + } + /> + + + ); +}; diff --git a/frontend/src/providers/app.tsx b/frontend/src/providers/app.tsx index eeee5f4e..f13dff97 100644 --- a/frontend/src/providers/app.tsx +++ b/frontend/src/providers/app.tsx @@ -1,38 +1,32 @@ +import { AuthenticationProvider } from "@context/authentication"; +import { StorageProvider } from "@context/storage/useStorage"; import CssBaseline from "@mui/material/CssBaseline"; import { ThemeProvider } from "@mui/material/styles"; -import { AuthenticationProvider } from "context/authentication"; -import { StorageProvider } from "context/storage/useStorage"; -import { WorkspacesProvider } from "context/workspaces"; -import PiecesProvider from "context/workspaces/repositories"; +import { queryClient } from "@services/clients/react-query.client"; +import { QueryClientProvider } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { type FC } from "react"; import { BrowserRouter } from "react-router-dom"; import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; -import { SWRConfig } from "swr"; -import ApplicationRoutes from "../routes"; +import { AppRoutes } from "../routes"; import { theme } from "./theme.config"; -/** - * @todo add more things such as Toast Container and Auth Provider - * @returns - */ export const App: FC = () => ( - - - - - - - - - - - - + + + + + + + + + + ); diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index 16c8d7ca..62592124 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -1,124 +1,15 @@ -import Loading from "components/Loading"; -import { - WorkspaceSettingsPage, - WorkspacesPage, -} from "features/workspaces/pages"; -import { Suspense, type FC } from "react"; -import { Navigate, Route, Routes } from "react-router-dom"; -import { lazyImport } from "utils"; +import { useAuthentication } from "@context/authentication"; +import { useRoutes } from "react-router-dom"; -import { PrivateRoute } from "./privateRoute"; -import { PublicRoute } from "./publicRoute"; +import { protectedRoutes } from "./protected"; +import { publicRoutes } from "./public"; -const { SignInPage } = lazyImport( - async () => await import("features/auth/pages/signIn/signInPage"), - "SignInPage", -); -const { SignUpPage } = lazyImport( - async () => await import("features/auth/pages/signUp/signUpPage"), - "SignUpPage", -); -const { WorkflowsEditorPage } = lazyImport( - async () => await import("features/workflowEditor/pages"), - "WorkflowsEditorPage", -); -const { WorkflowsPage } = lazyImport( - async () => await import("features/myWorkflows/pages"), - "WorkflowsPage", -); -const { WorkflowDetailPage } = lazyImport( - async () => await import("features/myWorkflows/pages"), - "WorkflowDetailPage", -); -const { ResultsReportPage } = lazyImport( - async () => await import("features/myWorkflows/pages"), - "ResultsReportPage", -); +export const AppRoutes = () => { + const { isLogged } = useAuthentication(); -/** - * Application router - * @todo implement recover password pages - * @todo implement error (404, ...) pages - * @returns app router component - */ -export const ApplicationRoutes: FC = () => ( - - - - } - > - - } /> + const routes = isLogged ? protectedRoutes : publicRoutes; - } - /> + const element = useRoutes([...routes]); - } - /> - - {/** @todo implement page */} -

Recover password

} /> - } - /> - - } - /> - - - } - /> - - } - /> - - - } - /> - - - } - /> - - - } - /> - - {/** @todo implement page */} -

404 not found

} /> - } - /> - - } /> -
-
-); - -export default ApplicationRoutes; + return <>{element}; +}; diff --git a/frontend/src/routes/privateRoute.tsx b/frontend/src/routes/privateRoute.tsx deleted file mode 100644 index 30a048c9..00000000 --- a/frontend/src/routes/privateRoute.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useAuthentication } from "context/authentication"; -import { useWorkspaces } from "context/workspaces"; -import { type FC } from "react"; -import { Navigate } from "react-router-dom"; - -interface IPrivateRouteProps { - /** - * @todo type properly - */ - component: any; - - /** - * `true` if this route is accessible only after selecting a workspace - * @default false - * */ - requireWorkspace?: boolean; -} - -/** - * Declares a route as private and checks for authentication & workspace. - */ -export const PrivateRoute: FC = ({ - component: Component, - requireWorkspace, -}) => { - const { isLogged } = useAuthentication(); - const { workspace } = useWorkspaces(); - - /** - * @todo simplify, **especially** if we have to add another state (maybe state machine?) - * isLogged | requireWorkspace | !!workspace | page - * TRUE TRUE TRUE go - * TRUE TRUE FALSE /workspaces - * TRUE FALSE TRUE go - * TRUE FALSE FALSE go - * FALSE TRUE TRUE /sign-in - * FALSE TRUE FALSE /sign-in - * FALSE FALSE TRUE /sign-in - * FALSE FALSE FALSE /sign-in - */ - - switch (true) { - case isLogged && requireWorkspace && !workspace: - return ; - - case isLogged && requireWorkspace && !!workspace: - case isLogged && !requireWorkspace: - return ; - - default: - return ; - } -}; diff --git a/frontend/src/routes/protected.tsx b/frontend/src/routes/protected.tsx new file mode 100644 index 00000000..422a8f3d --- /dev/null +++ b/frontend/src/routes/protected.tsx @@ -0,0 +1,76 @@ +import PrivateLayout from "@components/PrivateLayout"; +import { NotFoundRoute } from "@components/Routes/NotFoundRoute"; +import { MyWorkflowsRoutes } from "@features/myWorkflows/routes"; +import { WorkflowEditorRoute } from "@features/workflowEditor/routes"; +import { WorkspaceRoute } from "@features/workspaces/routes"; +import { Box } from "@mui/material"; +import Loading from "components/Loading"; +import { useAuthentication } from "context/authentication"; +import { WorkspacesProvider } from "context/workspaces"; +import PiecesProvider from "context/workspaces/repositories"; +import React, { Suspense } from "react"; +import { Navigate, Outlet, redirect } from "react-router-dom"; +// import { lazyImport } from "utils"; + +const App = () => { + const { isLogged } = useAuthentication(); + + if (!isLogged) { + redirect("/sign-in"); + } + + return ( + + + + } + > + + + + + + + ); +}; + +export const protectedRoutes = [ + { + path: "/*", + element: , + + children: [ + { path: "workspaces/*", element: }, + { path: "my-workflows/*", element: }, + { path: "workflows-editor/*", element: }, + { + path: "unauthorized", + element:
Unauthorized
, + }, + { + path: "404", + element: ( + + + + ), + }, + { + path: "*", + element: ( + + ), + }, + ], + }, +]; diff --git a/frontend/src/routes/public.tsx b/frontend/src/routes/public.tsx new file mode 100644 index 00000000..098cb881 --- /dev/null +++ b/frontend/src/routes/public.tsx @@ -0,0 +1,9 @@ +import { AuthRoutes } from "@features/auth/routes"; +import React from "react"; + +export const publicRoutes = [ + { + path: "/*", + element: , + }, +]; diff --git a/frontend/src/routes/publicRoute.tsx b/frontend/src/routes/publicRoute.tsx deleted file mode 100644 index 2fa5563e..00000000 --- a/frontend/src/routes/publicRoute.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useAuthentication } from "context/authentication"; -import { type FC } from "react"; -import { Navigate } from "react-router-dom"; - -export interface IPublicRouteProps { - /** - * @todo type properly - */ - component: any; - /** - * `true` if this route is accessible only for not authenticated users - * @default false - * */ - publicOnly?: boolean; -} - -/** - * Declares a route as public. - */ -export const PublicRoute: FC = ({ - publicOnly, - component: Component, -}) => { - const { isLogged } = useAuthentication(); - return publicOnly && isLogged ? : ; -}; - -export default PublicRoute; diff --git a/frontend/src/services/clients/domino.client.ts b/frontend/src/services/clients/domino.client.ts index 65703fd1..c36e3d45 100644 --- a/frontend/src/services/clients/domino.client.ts +++ b/frontend/src/services/clients/domino.client.ts @@ -1,28 +1,29 @@ import axios from "axios"; -import { environment } from "config/environment.config"; import { dispatchLogout } from "context/authentication"; import { toast } from "react-toastify"; import { endpoint } from "../config/endpoints.config"; -import { dominoMock } from "./domino.mock"; - export const dominoApiClient = axios.create({ baseURL: endpoint, }); -if (environment.USE_MOCK) { - console.info( - "⚠ info: using mock for requests, they may be out of sync with current backend development", - ); - dominoMock(); -} +dominoApiClient.interceptors.request.use( + (config) => { + const token = localStorage.getItem("auth_token"); + if (token) { + config.headers = config.headers ?? {}; + config.headers.Authorization = `Bearer ${token}`; + } + return config; + }, + async (error) => { + return await Promise.reject(error); + }, +); -/** - * @todo handle unauthorized and other useful status codes - */ dominoApiClient.interceptors.response.use( - (response) => response, + (response) => response.data, async (error) => { if (error.response.status === 401) { dispatchLogout(); @@ -35,29 +36,15 @@ dominoApiClient.interceptors.response.use( "Something went wrong"; if (Array.isArray(message)) { - toast.error(message[0].msg); + toast.error(message[0].msg, { + toastId: message[0].msg, + }); } else { - toast.error(message); + toast.error(message, { + toastId: message, + }); } return await Promise.reject(error); }, ); - -// Set header from storage on each request using interceptors -dominoApiClient.interceptors.request.use( - (config) => { - const token = localStorage.getItem("auth_token"); - if (token) { - config.headers = config.headers ?? {}; - config.headers.Authorization = `Bearer ${token}`; - } else { - config.headers = config.headers ?? {}; - config.headers.Authorization = `Bearer ${token}`; - } - return config; - }, - async (error) => { - return await Promise.reject(error); - }, -); diff --git a/frontend/src/services/clients/domino.mock.ts b/frontend/src/services/clients/domino.mock.ts deleted file mode 100644 index 1e9e2922..00000000 --- a/frontend/src/services/clients/domino.mock.ts +++ /dev/null @@ -1,20 +0,0 @@ -import MockAdapter from "axios-mock-adapter"; -import { - postAuthLoginMockResponse, - postAuthRegisterMockResponse, -} from "context/authentication/api"; - -import { dominoApiClient } from "./domino.client"; - -export const dominoMock = () => { - const dominoApiMockAdapter = new MockAdapter(dominoApiClient, { - delayResponse: 3000, - onNoMatch: "passthrough", - }); - dominoApiMockAdapter - .onPost("/auth/login") - .reply(200, postAuthLoginMockResponse); - dominoApiMockAdapter - .onPost("/auth/register") - .reply(200, postAuthRegisterMockResponse); -}; diff --git a/frontend/src/services/clients/react-query.client.ts b/frontend/src/services/clients/react-query.client.ts new file mode 100644 index 00000000..e8f9c48f --- /dev/null +++ b/frontend/src/services/clients/react-query.client.ts @@ -0,0 +1,39 @@ +import { + QueryClient, + type UseQueryOptions, + type UseMutationOptions, + type DefaultOptions, + type UseInfiniteQueryOptions, + type InfiniteData, +} from "@tanstack/react-query"; +import { type AxiosError } from "axios"; + +const queryConfig: DefaultOptions = { + queries: { + refetchOnWindowFocus: true, + retry: false, + }, +}; + +export const queryClient = new QueryClient({ defaultOptions: queryConfig }); + +export type QueryConfig = Omit< + UseQueryOptions, + "queryKey" | "queryFn" +>; + +export type InfiniteQueryConfig = Omit< + UseInfiniteQueryOptions< + T, + AxiosError, + InfiniteData, + T, + Array, + number + >, + "queryKey" | "queryFn" | "getNextPageParam" | "initialPageParam" +>; +export type MutationConfig = Omit< + UseMutationOptions, + "mutationKey" | "mutationFn" +>; diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts index 6f710cd8..d3f81969 100644 --- a/frontend/src/utils/index.ts +++ b/frontend/src/utils/index.ts @@ -9,3 +9,4 @@ export { useMouseProximity } from "./useMouseProximity"; export { exportToJson } from "./downloadJson"; export { isEmpty } from "./isEmpty"; export { secondsToHMS } from "./datetime"; +export * from "./roles"; diff --git a/frontend/src/utils/roles.ts b/frontend/src/utils/roles.ts new file mode 100644 index 00000000..01a818d4 --- /dev/null +++ b/frontend/src/utils/roles.ts @@ -0,0 +1,6 @@ +export enum role { + owner = "owner", + read = "read", +} + +export type Roles = `${role}`; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index cd18756e..87f00c17 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -7,7 +7,15 @@ "esnext" ], "types": ["vite/client", "vite-plugin-svgr/client"], - "baseUrl": "src", + "baseUrl": "./src", + "paths": { + "@components/*": ["components/*"], + "@config/*": ["config/*"], + "@context/*": ["context/*"], + "@features/*": ["features/*"], + "@services/*": ["services/*"], + "@utils/*": ["utils/*"] + }, "allowJs": true, "skipLibCheck": true, "esModuleInterop": true,