From 31efb2e04db209ac11f57f6d5b5fef6c8fd978a2 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 4 Jun 2024 18:37:05 +0200 Subject: [PATCH 01/17] setup image-labeler project --- apps/image-labeler/.dockerignore | 1 + apps/image-labeler/.eslintrc.json | 18 + apps/image-labeler/Dockerfile | 24 + apps/image-labeler/cloudbuild.yaml | 110 ++ apps/image-labeler/docker-compose.yaml | 13 + apps/image-labeler/index.html | 16 + apps/image-labeler/nginx.conf | 48 + apps/image-labeler/project.json | 57 + apps/image-labeler/public/favicon.ico | Bin 0 -> 15086 bytes apps/image-labeler/src/app/app.module.css | 1 + apps/image-labeler/src/app/app.tsx | 49 + apps/image-labeler/src/assets/.gitkeep | 0 apps/image-labeler/src/main.tsx | 13 + apps/image-labeler/src/styles.css | 1 + apps/image-labeler/tsconfig.app.json | 23 + apps/image-labeler/tsconfig.json | 21 + apps/image-labeler/tsconfig.spec.json | 28 + apps/image-labeler/vite.config.mts | 65 + nx.json | 24 + package.json | 13 +- tsconfig.base.json | 4 +- vitest.workspace.ts | 1 + yarn.lock | 1580 ++++++++++++++++++++- 23 files changed, 2065 insertions(+), 45 deletions(-) create mode 100644 apps/image-labeler/.dockerignore create mode 100644 apps/image-labeler/.eslintrc.json create mode 100644 apps/image-labeler/Dockerfile create mode 100644 apps/image-labeler/cloudbuild.yaml create mode 100644 apps/image-labeler/docker-compose.yaml create mode 100644 apps/image-labeler/index.html create mode 100644 apps/image-labeler/nginx.conf create mode 100644 apps/image-labeler/project.json create mode 100644 apps/image-labeler/public/favicon.ico create mode 100644 apps/image-labeler/src/app/app.module.css create mode 100644 apps/image-labeler/src/app/app.tsx create mode 100644 apps/image-labeler/src/assets/.gitkeep create mode 100644 apps/image-labeler/src/main.tsx create mode 100644 apps/image-labeler/src/styles.css create mode 100644 apps/image-labeler/tsconfig.app.json create mode 100644 apps/image-labeler/tsconfig.json create mode 100644 apps/image-labeler/tsconfig.spec.json create mode 100644 apps/image-labeler/vite.config.mts create mode 100644 vitest.workspace.ts diff --git a/apps/image-labeler/.dockerignore b/apps/image-labeler/.dockerignore new file mode 100644 index 0000000000..75db72a526 --- /dev/null +++ b/apps/image-labeler/.dockerignore @@ -0,0 +1 @@ +nginx.conf diff --git a/apps/image-labeler/.eslintrc.json b/apps/image-labeler/.eslintrc.json new file mode 100644 index 0000000000..d3e61a2ea8 --- /dev/null +++ b/apps/image-labeler/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../.eslintrc.js"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/apps/image-labeler/Dockerfile b/apps/image-labeler/Dockerfile new file mode 100644 index 0000000000..e29bb7d2cc --- /dev/null +++ b/apps/image-labeler/Dockerfile @@ -0,0 +1,24 @@ +################################################################################# +# Generate htpasswd file +################################################################################# +# FROM appsoa/docker-alpine-htpasswd as htpasswd +# ARG BASIC_AUTH_USER=gfw +# ARG BASIC_AUTH_PASS=default +# ENV BASIC_AUTH_USER $BASIC_AUTH_USER +# ENV BASIC_AUTH_PASS $BASIC_AUTH_PASS +# RUN htpasswd -Bbn "$BASIC_AUTH_USER" "$BASIC_AUTH_PASS" > /home/.htpasswd + +################################################################################# +# Actual application to run +################################################################################# +# Using stable version that uses alpine 3.14 to fix build errors +# https://github.com/alpinelinux/docker-alpine/issues/182 +FROM nginx:stable-alpine as production + +COPY ./nginx.conf /etc/nginx/nginx.conf +# COPY --from=htpasswd /home/.htpasswd /home/.htpasswd +# RUN cat /home/.htpasswd >> /etc/nginx/.htpasswd +# COPY ./entrypoint.sh entrypoint.sh +COPY ./ /usr/share/nginx/www/ +# ENTRYPOINT ["./entrypoint.sh"] + diff --git a/apps/image-labeler/cloudbuild.yaml b/apps/image-labeler/cloudbuild.yaml new file mode 100644 index 0000000000..bcff17381e --- /dev/null +++ b/apps/image-labeler/cloudbuild.yaml @@ -0,0 +1,110 @@ +steps: + - name: 'gcr.io/$PROJECT_ID/restore_cache' + id: restore_cache + waitFor: ['-'] + script: | + #!/usr/bin/env bash + restore_cache \ + --bucket=gs://frontend-cache-dependencies \ + --key=node_modules-$( checksum yarn.lock ) + restore_cache \ + --bucket=gs://frontend-cache-dependencies \ + --key=yarn-$( checksum yarn.lock ) + restore_cache \ + --bucket=gs://frontend-cache-dependencies \ + --key=yarn-install-state-$( checksum yarn.lock ) + + - id: 'install-yarn' + waitFor: ['restore_cache'] + name: node:21 + script: | + yarn set version 4.2.2 + yarn -v + yarn install --immutable + + - id: 'save_cache' + waitFor: ['install-yarn'] + name: 'gcr.io/$PROJECT_ID/restore_cache' + script: | + #!/usr/bin/env bash + save_cache \ + --bucket=gs://frontend-cache-dependencies \ + --key=node_modules-$( checksum yarn.lock ) \ + --path=./node_modules \ + --no-clobber + save_cache \ + --bucket=gs://frontend-cache-dependencies \ + --key=yarn-$( checksum yarn.lock ) \ + --path=.yarn/cache \ + --no-clobber + save_cache \ + --bucket=gs://frontend-cache-dependencies \ + --key=yarn-install-state-$( checksum yarn.lock ) \ + --path=.yarn/install-state.gz \ + --no-clobber + + - id: 'build-app' + waitFor: ['install-yarn'] + name: node:21 + entrypoint: yarn + args: ['nx', 'build', 'image-labeler', '--parallel'] + env: + - 'NX_BRANCH=$_NX_BRANCH' + - 'NX_CLOUD_AUTH_TOKEN=$_NX_CLOUD_AUTH_TOKEN' + - 'NEXT_PUBLIC_API_GATEWAY=$_NEXT_PUBLIC_API_GATEWAY' + + - id: 'docker-prepare' + waitFor: ['build-app'] + name: node:21 + entrypoint: yarn + args: ['nx', 'docker-prepare', 'image-labeler'] + + - name: 'gcr.io/kaniko-project/executor:latest' + id: 'build-image' + waitFor: ['docker-prepare'] + args: + [ + '--destination=gcr.io/world-fishing-827/github.com/globalfishingwatch/image-labeler:$SHORT_SHA', + '--cache=true', + '--build-arg', + 'BASIC_AUTH_USER=$_BASIC_AUTH_USER', + '--build-arg', + 'BASIC_AUTH_PASS=$_BASIC_AUTH_PASS', + '--target', + 'production', + '-f', + './apps/image-labeler/Dockerfile', + '-c', + './dist/apps/image-labeler', + ] + + # Deploy to the appropriate environment + - name: 'gcr.io/cloud-builders/gcloud' + waitFor: ['build-image'] + id: 'deploy-cloud-run' + entrypoint: 'bash' + env: + - '_RUN_SERVICE_NAME=$_RUN_SERVICE_NAME' + args: + - '-eEuo' + - 'pipefail' + - '-c' + - |- + branch_service_name=`echo image-labeler-$BRANCH_NAME | sed -r 's,[/\.],-,g' | awk '{print substr(tolower($0),0,62)}'` + service_name=${_RUN_SERVICE_NAME:-${branch_service_name}} + gcloud beta run deploy \ + $service_name \ + --project \ + $_RUN_PROJECT \ + --image \ + gcr.io/world-fishing-827/github.com/globalfishingwatch/image-labeler:$SHORT_SHA \ + --region \ + $_RUN_REGION \ + --platform managed \ + --set-env-vars \ + BASIC_AUTH=$_BASIC_AUTH \ + --allow-unauthenticated + +timeout: 1800s +options: + machineType: 'E2_HIGHCPU_8' diff --git a/apps/image-labeler/docker-compose.yaml b/apps/image-labeler/docker-compose.yaml new file mode 100644 index 0000000000..3b5c800663 --- /dev/null +++ b/apps/image-labeler/docker-compose.yaml @@ -0,0 +1,13 @@ +services: + image-labeler: + build: + context: ../../dist/apps/image-labeler + dockerfile: ../../../apps/image-labeler/Dockerfile + target: production + container_name: image-labeler + ports: + - 3000:80 + env_file: + - .env + environment: + - API_GATEWAY=https://gateway.api.dev.globalfishingwatch.org diff --git a/apps/image-labeler/index.html b/apps/image-labeler/index.html new file mode 100644 index 0000000000..c98a53db73 --- /dev/null +++ b/apps/image-labeler/index.html @@ -0,0 +1,16 @@ + + + + + ImageLabeler + + + + + + + +
+ + + diff --git a/apps/image-labeler/nginx.conf b/apps/image-labeler/nginx.conf new file mode 100644 index 0000000000..61df99eb29 --- /dev/null +++ b/apps/image-labeler/nginx.conf @@ -0,0 +1,48 @@ +events { + worker_connections 1024; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + include /etc/nginx/mime.types; + default_type application/octet-stream; + client_header_buffer_size 64k; + large_client_header_buffers 4 64k; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log warn; + + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + # Specify the minimum length of the response to compress (default 20) + gzip_min_length 100; + + server { + listen 80; + root /usr/share/nginx/www/; + + location ~* ^/image-labeler/(.+\..+)$ { + alias /usr/share/nginx/www/$1; + } + + location ~* ^/(.+\..+)$ { + alias /usr/share/nginx/www/$1; + } + + location / { + # auth_basic ${BASIC_AUTH}; + # auth_basic_user_file /etc/nginx/.htpasswd; + try_files $uri $uri/ /index.html; + } + } +} diff --git a/apps/image-labeler/project.json b/apps/image-labeler/project.json new file mode 100644 index 0000000000..abaf83f8ea --- /dev/null +++ b/apps/image-labeler/project.json @@ -0,0 +1,57 @@ +{ + "name": "image-labeler", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/image-labeler/src", + "projectType": "application", + "tags": [], + "targets": { + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/apps/image-labeler" + }, + "configurations": { + "development": { + "mode": "development" + }, + "production": { + "mode": "production" + } + } + }, + "start": { + "executor": "@nx/vite:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "image-labeler:build" + }, + "configurations": { + "development": { + "buildTarget": "image-labeler:build:development", + "hmr": true + }, + "production": { + "buildTarget": "image-labeler:build:production", + "hmr": false + } + } + }, + "preview": { + "executor": "@nx/vite:preview-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "image-labeler:build" + }, + "configurations": { + "development": { + "buildTarget": "image-labeler:build:development" + }, + "production": { + "buildTarget": "image-labeler:build:production" + } + } + } + } +} diff --git a/apps/image-labeler/public/favicon.ico b/apps/image-labeler/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 zcmeI332;U^%p|z7g|#(P)qFEA@4f!_@qOK2 z_lJl}!lhL!VT_U|uN7%8B2iKH??xhDa;*`g{yjTFWHvXn;2s{4R7kH|pKGdy(7z!K zgftM+Ku7~24TLlh(!g)gz|foI94G^t2^IO$uvX$3(OR0<_5L2sB)lMAMy|+`xodJ{ z_Uh_1m)~h?a;2W{dmhM;u!YGo=)OdmId_B<%^V^{ovI@y`7^g1_V9G}*f# zNzAtvou}I!W1#{M^@ROc(BZ! z+F!!_aR&Px3_reO(EW+TwlW~tv*2zr?iP7(d~a~yA|@*a89IUke+c472NXM0wiX{- zl`UrZC^1XYyf%1u)-Y)jj9;MZ!SLfd2Hl?o|80Su%Z?To_=^g_Jt0oa#CT*tjx>BI z16wec&AOWNK<#i0Qd=1O$fymLRoUR*%;h@*@v7}wApDl^w*h}!sYq%kw+DKDY)@&A z@9$ULEB3qkR#85`lb8#WZw=@})#kQig9oqy^I$dj&k4jU&^2(M3q{n1AKeGUKPFbr z1^<)aH;VsG@J|B&l>UtU#Ejv3GIqERzYgL@UOAWtW<{p#zy`WyJgpCy8$c_e%wYJL zyGHRRx38)HyjU3y{-4z6)pzb>&Q1pR)B&u01F-|&Gx4EZWK$nkUkOI|(D4UHOXg_- zw{OBf!oWQUn)Pe(=f=nt=zkmdjpO^o8ZZ9o_|4tW1ni+Un9iCW47*-ut$KQOww!;u z`0q)$s6IZO!~9$e_P9X!hqLxu`fpcL|2f^I5d4*a@Dq28;@2271v_N+5HqYZ>x;&O z05*7JT)mUe&%S0@UD)@&8SmQrMtsDfZT;fkdA!r(S=}Oz>iP)w=W508=Rc#nNn7ym z1;42c|8($ALY8#a({%1#IXbWn9-Y|0eDY$_L&j{63?{?AH{);EzcqfydD$@-B`Y3<%IIj7S7rK_N}je^=dEk%JQ4c z!tBdTPE3Tse;oYF>cnrapWq*o)m47X1`~6@(!Y29#>-#8zm&LXrXa(3=7Z)ElaQqj z-#0JJy3Fi(C#Rx(`=VXtJ63E2_bZGCz+QRa{W0e2(m3sI?LOcUBx)~^YCqZ{XEPX)C>G>U4tfqeH8L(3|pQR*zbL1 zT9e~4Tb5p9_G}$y4t`i*4t_Mr9QYvL9C&Ah*}t`q*}S+VYh0M6GxTTSXI)hMpMpIq zD1ImYqJLzbj0}~EpE-aH#VCH_udYEW#`P2zYmi&xSPs_{n6tBj=MY|-XrA;SGA_>y zGtU$?HXm$gYj*!N)_nQ59%lQdXtQZS3*#PC-{iB_sm+ytD*7j`D*k(P&IH2GHT}Eh z5697eQECVIGQAUe#eU2I!yI&%0CP#>%6MWV z@zS!p@+Y1i1b^QuuEF*13CuB zu69dve5k7&Wgb+^s|UB08Dr3u`h@yM0NTj4h7MnHo-4@xmyr7(*4$rpPwsCDZ@2be zRz9V^GnV;;?^Lk%ynzq&K(Aix`mWmW`^152Hoy$CTYVehpD-S1-W^#k#{0^L`V6CN+E z!w+xte;2vu4AmVNEFUOBmrBL>6MK@!O2*N|2=d|Y;oN&A&qv=qKn73lDD zI(+oJAdgv>Yr}8(&@ZuAZE%XUXmX(U!N+Z_sjL<1vjy1R+1IeHt`79fnYdOL{$ci7 z%3f0A*;Zt@ED&Gjm|OFTYBDe%bbo*xXAQsFz+Q`fVBH!N2)kaxN8P$c>sp~QXnv>b zwq=W3&Mtmih7xkR$YA)1Yi?avHNR6C99!u6fh=cL|KQ&PwF!n@ud^n(HNIImHD!h87!i*t?G|p0o+eelJ?B@A64_9%SBhNaJ64EvKgD&%LjLCYnNfc; znj?%*p@*?dq#NqcQFmmX($wms@CSAr9#>hUR^=I+=0B)vvGX%T&#h$kmX*s=^M2E!@N9#m?LhMvz}YB+kd zG~mbP|D(;{s_#;hsKK9lbVK&Lo734x7SIFJ9V_}2$@q?zm^7?*XH94w5Qae{7zOMUF z^?%F%)c1Y)Q?Iy?I>knw*8gYW#ok|2gdS=YYZLiD=CW|Nj;n^x!=S#iJ#`~Ld79+xXpVmUK^B(xO_vO!btA9y7w3L3-0j-y4 z?M-V{%z;JI`bk7yFDcP}OcCd*{Q9S5$iGA7*E1@tfkyjAi!;wP^O71cZ^Ep)qrQ)N z#wqw0_HS;T7x3y|`P==i3hEwK%|>fZ)c&@kgKO1~5<5xBSk?iZV?KI6&i72H6S9A* z=U(*e)EqEs?Oc04)V-~K5AUmh|62H4*`UAtItO$O(q5?6jj+K^oD!04r=6#dsxp?~}{`?&sXn#q2 zGuY~7>O2=!u@@Kfu7q=W*4egu@qPMRM>(eyYyaIE<|j%d=iWNdGsx%c!902v#ngNg z@#U-O_4xN$s_9?(`{>{>7~-6FgWpBpqXb`Ydc3OFL#&I}Irse9F_8R@4zSS*Y*o*B zXL?6*Aw!AfkNCgcr#*yj&p3ZDe2y>v$>FUdKIy_2N~}6AbHc7gA3`6$g@1o|dE>vz z4pl(j9;kyMsjaw}lO?(?Xg%4k!5%^t#@5n=WVc&JRa+XT$~#@rldvN3S1rEpU$;XgxVny7mki3 z-Hh|jUCHrUXuLr!)`w>wgO0N%KTB-1di>cj(x3Bav`7v z3G7EIbU$z>`Nad7Rk_&OT-W{;qg)-GXV-aJT#(ozdmnA~Rq3GQ_3mby(>q6Ocb-RgTUhTN)))x>m&eD;$J5Bg zo&DhY36Yg=J=$Z>t}RJ>o|@hAcwWzN#r(WJ52^g$lh^!63@hh+dR$&_dEGu&^CR*< z!oFqSqO@>xZ*nC2oiOd0eS*F^IL~W-rsrO`J`ej{=ou_q^_(<$&-3f^J z&L^MSYWIe{&pYq&9eGaArA~*kA + } + return ( +
+
+
    +
  • + Home +
  • +
  • + Page 2 +
  • +
+
+ + + This is the generated root route. Click here for page 2. +
+ } + /> + + Click here to go back to root page. + + } + /> + + {/* END: routes */} + + ) +} + +export default App diff --git a/apps/image-labeler/src/assets/.gitkeep b/apps/image-labeler/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/image-labeler/src/main.tsx b/apps/image-labeler/src/main.tsx new file mode 100644 index 0000000000..e5880901e9 --- /dev/null +++ b/apps/image-labeler/src/main.tsx @@ -0,0 +1,13 @@ +import { StrictMode } from 'react' +import * as ReactDOM from 'react-dom/client' +import { BrowserRouter } from 'react-router-dom' +import App from './app/app' + +const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement) +root.render( + + + + + +) diff --git a/apps/image-labeler/src/styles.css b/apps/image-labeler/src/styles.css new file mode 100644 index 0000000000..90d4ee0072 --- /dev/null +++ b/apps/image-labeler/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/image-labeler/tsconfig.app.json b/apps/image-labeler/tsconfig.app.json new file mode 100644 index 0000000000..cd44a1e78f --- /dev/null +++ b/apps/image-labeler/tsconfig.app.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": [ + "node", + "@nx/react/typings/cssmodule.d.ts", + "@nx/react/typings/image.d.ts", + "vite/client" + ] + }, + "exclude": [ + "src/**/*.spec.ts", + "src/**/*.test.ts", + "src/**/*.spec.tsx", + "src/**/*.test.tsx", + "src/**/*.spec.js", + "src/**/*.test.js", + "src/**/*.spec.jsx", + "src/**/*.test.jsx" + ], + "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] +} diff --git a/apps/image-labeler/tsconfig.json b/apps/image-labeler/tsconfig.json new file mode 100644 index 0000000000..fdfab6c30f --- /dev/null +++ b/apps/image-labeler/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client", "vitest"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/apps/image-labeler/tsconfig.spec.json b/apps/image-labeler/tsconfig.spec.json new file mode 100644 index 0000000000..6d181f7f6e --- /dev/null +++ b/apps/image-labeler/tsconfig.spec.json @@ -0,0 +1,28 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest", + "@nx/react/typings/cssmodule.d.ts", + "@nx/react/typings/image.d.ts" + ] + }, + "include": [ + "vite.config.mts", + "vitest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/apps/image-labeler/vite.config.mts b/apps/image-labeler/vite.config.mts new file mode 100644 index 0000000000..70c10c4d6c --- /dev/null +++ b/apps/image-labeler/vite.config.mts @@ -0,0 +1,65 @@ +/// +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import { viteStaticCopy } from 'vite-plugin-static-copy' +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' + +export default defineConfig({ + root: __dirname, + cacheDir: '../../node_modules/.vite/apps/image-labeler', + + server: { + port: 3000, + host: 'localhost', + }, + + preview: { + port: 3001, + host: 'localhost', + }, + + plugins: [ + react(), + nxViteTsPaths(), + viteStaticCopy({ + targets: [ + { + src: 'nginx.conf', + dest: '', + }, + ], + }), + ], + + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + + build: { + outDir: '../../dist/apps/image-labeler', + reportCompressedSize: true, + commonjsOptions: { + transformMixedEsModules: true, + }, + }, + + define: { + 'process.env': {}, + }, + + // test: { + // globals: true, + // cache: { + // dir: '../../node_modules/.vitest', + // }, + // environment: 'jsdom', + // include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + + // reporters: ['default'], + // coverage: { + // reportsDirectory: '../../coverage/apps/image-labeler', + // provider: 'v8', + // }, + // }, +}) diff --git a/nx.json b/nx.json index b214918464..ee4554ec26 100644 --- a/nx.json +++ b/nx.json @@ -49,6 +49,15 @@ "cache": true, "dependsOn": ["^build", "^dist"], "inputs": ["production", "^production"] + }, + "@nx/vite:test": { + "cache": true, + "inputs": ["default", "^production"] + }, + "@nx/vite:build": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["production", "^production"] } }, "generators": { @@ -57,6 +66,21 @@ "style": "css", "linter": "eslint" } + }, + "@nx/react": { + "application": { + "babel": true, + "style": "css", + "linter": "eslint", + "bundler": "vite" + }, + "component": { + "style": "css" + }, + "library": { + "style": "css", + "linter": "eslint" + } } }, "release": { diff --git a/package.json b/package.json index 332c1c28d9..d64a49a84a 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,7 @@ "react-query": "^3.39.3", "react-range": "^1.8.14", "react-redux": "^9.1.0", + "react-router-dom": "6.11.2", "react-spring": "^9.7.3", "react-sticky-el": "2.1.0", "react-virtualized-auto-sizer": "^1.0.20", @@ -149,7 +150,9 @@ "@nx/jest": "18.3.3", "@nx/js": "18.3.3", "@nx/next": "18.3.3", + "@nx/react": "18.3.3", "@nx/rollup": "18.3.3", + "@nx/vite": "18.3.3", "@nx/web": "18.3.3", "@nx/workspace": "18.3.3", "@rollup/plugin-wasm": "^6.2.2", @@ -158,6 +161,7 @@ "@swc/cli": "~0.1.62", "@swc/core": "~1.3.85", "@swc/helpers": "~0.5.2", + "@testing-library/react": "14.0.0", "@types/circular-dependency-plugin": "^5.0.8", "@types/d3": "^7.4.3", "@types/d3-array": "^3.2.1", @@ -187,6 +191,9 @@ "@typescript-eslint/eslint-plugin": "7.6.0", "@typescript-eslint/parser": "7.6.0", "@typescript-eslint/scope-manager": "7.0.1", + "@vitejs/plugin-react": "^4.2.0", + "@vitest/coverage-v8": "^1.0.4", + "@vitest/ui": "^1.3.1", "babel-jest": "^29.4.1", "circular-dependency-plugin": "^5.2.2", "cypress": "^13.7.3", @@ -207,6 +214,7 @@ "husky": "^9.0.11", "jest": "^29.4.1", "jest-environment-jsdom": "^29.4.1", + "jsdom": "~22.1.0", "lint-staged": "^15.2.2", "load-json-file": "^6.2.0", "mochawesome": "^7.1.3", @@ -220,7 +228,10 @@ "stylelint-config-standard": "36.0.0", "ts-jest": "^29.1.0", "ts-node": "10.9.1", - "typescript": "5.4.5" + "typescript": "5.4.5", + "vite": "~5.0.0", + "vite-plugin-static-copy": "^1.0.5", + "vitest": "^1.3.1" }, "resolutions": { "@popperjs/core": "2.10.2", diff --git a/tsconfig.base.json b/tsconfig.base.json index 72ce34921e..db64ab244c 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -32,8 +32,10 @@ "@globalfishingwatch/ocean-areas": ["libs/ocean-areas/src/index.ts"], "@globalfishingwatch/pbf-decoders": ["libs/pbf-decoders/index.ts"], "@globalfishingwatch/react-hooks": ["libs/react-hooks/src/index.ts"], + "@globalfishingwatch/react-hooks/*": ["libs/react-hooks/src/*"], "@globalfishingwatch/timebar": ["libs/timebar/src/index.js"], - "@globalfishingwatch/ui-components": ["libs/ui-components/src/index.ts"] + "@globalfishingwatch/ui-components": ["libs/ui-components/src/index.ts"], + "@globalfishingwatch/ui-components/*": ["libs/ui-components/src/*"] } }, "files": ["./vendors.d.ts"], diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 0000000000..8fdaf1ece9 --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1 @@ +export default ['**/*/vite.config.ts', '**/*/vitest.config.ts'] diff --git a/yarn.lock b/yarn.lock index c0dfd27242..528ebc0e93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,7 +29,7 @@ __metadata: languageName: node linkType: hard -"@ampproject/remapping@npm:^2.2.0": +"@ampproject/remapping@npm:^2.2.0, @ampproject/remapping@npm:^2.2.1": version: 2.3.0 resolution: "@ampproject/remapping@npm:2.3.0" dependencies: @@ -62,6 +62,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/code-frame@npm:7.24.6" + dependencies: + "@babel/highlight": "npm:^7.24.6" + picocolors: "npm:^1.0.0" + checksum: 10/e9b70af2a9c7c734ac36c2e6e1da640a6e0a483bfba7cf620226a1226a2e6d64961324b02d786e06ce72f0aa329e190dfc49128367a2368b69e2219ffddcdcc5 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4": version: 7.24.4 resolution: "@babel/compat-data@npm:7.24.4" @@ -69,6 +79,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/compat-data@npm:7.24.6" + checksum: 10/c355141e4649ef6efa413d71cfc1efb183be46b8fc945fc17e3c7f4313b4b566af575a4183450697916cd6b8c7f180e315986b5d7f07e7b7afd0786594754f7d + languageName: node + linkType: hard + "@babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.9": version: 7.24.4 resolution: "@babel/core@npm:7.24.4" @@ -92,6 +109,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.24.5": + version: 7.24.6 + resolution: "@babel/core@npm:7.24.6" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.24.6" + "@babel/generator": "npm:^7.24.6" + "@babel/helper-compilation-targets": "npm:^7.24.6" + "@babel/helper-module-transforms": "npm:^7.24.6" + "@babel/helpers": "npm:^7.24.6" + "@babel/parser": "npm:^7.24.6" + "@babel/template": "npm:^7.24.6" + "@babel/traverse": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10/49cd61b99984f0197f657690ec250fb68897de16180116ed0d4f66341eddd85757fd7ec20ba4fcf255990568515f3dd55248c30f1f831cbfaa1da4602a000e4e + languageName: node + linkType: hard + "@babel/eslint-parser@npm:^7.16.3": version: 7.24.1 resolution: "@babel/eslint-parser@npm:7.24.1" @@ -118,6 +158,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/generator@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^2.5.1" + checksum: 10/247002f1246c3cb825497dc7ce55dc1d10c5f0486f546d1c087aeed7e38df6eb7837758fdfa2ae1234c26c60f883756fd79b7b3f0443771bd79bdfbb0dde8cd4 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" @@ -149,6 +201,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-compilation-targets@npm:7.24.6" + dependencies: + "@babel/compat-data": "npm:^7.24.6" + "@babel/helper-validator-option": "npm:^7.24.6" + browserslist: "npm:^4.22.2" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10/28f34f2c9e0ec047360c4dca8d4fb99009e868f9c1acad0ca125f2f9990790897216155d44935209c6e4c4e0318f5a9a46304771d75823add7400e3079945314 + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4": version: 7.24.4 resolution: "@babel/helper-create-class-features-plugin@npm:7.24.4" @@ -203,6 +268,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-environment-visitor@npm:7.24.6" + checksum: 10/9c2b3f1ee7ba46b61b0482efab6d37f5c76f0ea4e9d9775df44a89644729c3a50101040a0233543ec6c3f416d8e548d337f310ff3e164f847945507428ee39e5 + languageName: node + linkType: hard + "@babel/helper-function-name@npm:^7.22.5, @babel/helper-function-name@npm:^7.23.0": version: 7.23.0 resolution: "@babel/helper-function-name@npm:7.23.0" @@ -213,6 +285,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-function-name@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-function-name@npm:7.24.6" + dependencies: + "@babel/template": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10/66c0669c16f9fd8b977303c3bd233f962a803de409f4a1db43d965c7cd3ddc12a07b82eb8e06624d76237726407b33fc6d6987a1e40e0c32fc1fc2c5be49340b + languageName: node + linkType: hard + "@babel/helper-hoist-variables@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-hoist-variables@npm:7.22.5" @@ -222,6 +304,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-hoist-variables@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-hoist-variables@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 10/4819b574393a5214aff6ae02a6e5250ace2564f8bcdb28d580ffec57bbb2092425e8f39563d75cfa268940a01fd425bad503c0b92717c12426f15cf6847855d3 + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.23.0": version: 7.23.0 resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" @@ -240,6 +331,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-module-imports@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 10/38c4432191219a10fe39178e148b295a353a802d3601ed219df6979d322b8179a57f37ee8c0d645f1304023a6b96c4aee351bf7cabe8036b294bfe3b9496ab43 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.23.3": version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" @@ -255,6 +355,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-module-transforms@npm:7.24.6" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-module-imports": "npm:^7.24.6" + "@babel/helper-simple-access": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/e162d0c1d876006d6989eadb9868be688784ea16a719cdce5df22541eac9547bebb137dc4d64f4d0349265b52a3633074a09c33785709e5c198696590d46402d + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" @@ -271,6 +386,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-plugin-utils@npm:7.24.6" + checksum: 10/0ac0a7a19959fb2f880ea87650475a4960232e98825d9a50f4aa56e5750a70fc799b48cf570af63a06b810d0128e758e801865762b51a8348067e37751a38478 + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" @@ -306,6 +428,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-simple-access@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-simple-access@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 10/4649d08f3e5eb30240f49ef7951b12d02ae4c30e6bef7b1b79ade587ff0b73223f3be840f6144b49c6b1a4a9dece890ada279b0844345ea8c011fb064fa2b9a3 + languageName: node + linkType: hard + "@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0, @babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" @@ -324,6 +455,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-split-export-declaration@npm:7.24.6" + dependencies: + "@babel/types": "npm:^7.24.6" + checksum: 10/48ded9611f87a23bc962c9cd576cc653bd78eab3d9987d3b1c18571481d0d17d7d29397a5c07a1f5e182ef1a1c6f420b9934975bf57e8d7cbcb8d8853cc21d6c + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.23.4": version: 7.24.1 resolution: "@babel/helper-string-parser@npm:7.24.1" @@ -331,6 +471,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-string-parser@npm:7.24.6" + checksum: 10/a24631e13850eb24a5e88fba4d1b86115a79f6d4a0b3a96641fdcdc4a6d706d7e09f17ae77fa26bc72a8a7253bc83b535a2e2865a78185ed1f957b299ea6c59c + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-validator-identifier@npm:7.22.20" @@ -338,6 +485,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-validator-identifier@npm:7.24.6" + checksum: 10/7e725ef0684291ca3306d5174a5d1cd9072ad58ba444cfa50aaf92a5c59dd723fa15031733ac598bb6b066cb62c2472e14cd82325522348977a72e99aa21b97a + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.23.5": version: 7.23.5 resolution: "@babel/helper-validator-option@npm:7.23.5" @@ -345,6 +499,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-validator-option@npm:7.24.6" + checksum: 10/5defb2da74e1cac9497016f4e41698aeed75ec7a5e9dc07e777cdb67ef73cd2e27bd2bf8a3ab8d37e0b93a6a45524a9728f03e263afdef452436cf74794bde87 + languageName: node + linkType: hard + "@babel/helper-wrap-function@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-wrap-function@npm:7.22.20" @@ -367,6 +528,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helpers@npm:7.24.6" + dependencies: + "@babel/template": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10/9043f7140651e89246d0653c7198832e644865038dc18c117c492d450f237514764d1476faa1ba7466b83b348891f10f564b0c5615d86d6833fb275ead7fb259 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.24.2": version: 7.24.2 resolution: "@babel/highlight@npm:7.24.2" @@ -379,6 +550,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/highlight@npm:7.24.6" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.24.6" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10/e11cd39ceb01c9b5e4f2684a45caefe7b2d7bb74997c30922e6b4063a6f16aff88356091350f0af01f044e1a198579a6b5c4161a84d0a6090e63a41167569daf + languageName: node + linkType: hard + "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1, @babel/parser@npm:^7.24.4": version: 7.24.4 resolution: "@babel/parser@npm:7.24.4" @@ -388,6 +571,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/parser@npm:7.24.6" + bin: + parser: ./bin/babel-parser.js + checksum: 10/48af4251d030623a8fbf22979fc718bd9dead6ba6a64cae717270c6c809faaf303d137d82593912291ee761130c4731f0c25feb54629ba3fa4edcc496690cb44 + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4": version: 7.24.4 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4" @@ -1285,6 +1477,28 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx-self@npm:^7.24.5": + version: 7.24.6 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.24.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/df6439705df24d6ac91ddc626c59a1a3733352d6bd48278a1be43a6d004f2300fc2a9d18766ec5a0c46211f7575d05a402a71d009fba65967349f551fad2e5a9 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-source@npm:^7.24.1": + version: 7.24.6 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.24.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/8719553710a2fde66e6ca2e44e947559219b2f9d370587d2bc0a55a7d34a02b15596852931ea9f53917ef13663c5aa789c62b5aacad5cb24f682bd4bf1a922e2 + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx@npm:^7.22.5, @babel/plugin-transform-react-jsx@npm:^7.23.4": version: 7.23.4 resolution: "@babel/plugin-transform-react-jsx@npm:7.23.4" @@ -1630,6 +1844,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/template@npm:7.24.6" + dependencies: + "@babel/code-frame": "npm:^7.24.6" + "@babel/parser": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10/e4641733dfb29b15f1b7f1a81579b3131d854d5aa2dc37a8b827e4eb6839c752cba45570934041b9f3dcf0edde8328f5313b092eaa6c7a342020b59d355f8bf5 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.16.0, @babel/traverse@npm:^7.24.1": version: 7.24.1 resolution: "@babel/traverse@npm:7.24.1" @@ -1648,6 +1873,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/traverse@npm:7.24.6" + dependencies: + "@babel/code-frame": "npm:^7.24.6" + "@babel/generator": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-function-name": "npm:^7.24.6" + "@babel/helper-hoist-variables": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" + "@babel/parser": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/11e5904f9aa255ac1470c6966e1898a718ea0cc7f41938a30df1a20dc31dfea34f66791a5ee0dd6d8d485230fe2e970d8301fa6908a524b3e7c96e52c0112ab6 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.24.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.24.0 resolution: "@babel/types@npm:7.24.0" @@ -1659,6 +1902,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/types@npm:7.24.6" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.6" + to-fast-properties: "npm:^2.0.0" + checksum: 10/34552539cdc740513650cb3c7754f77a55cc5253dff9d45afd52292d366eb1c099939d5db066e458abcf4c9a7dedfe43467445f9c2208b3cb64866762dee5e9d + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -2091,6 +2345,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/aix-ppc64@npm:0.19.12" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/aix-ppc64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/aix-ppc64@npm:0.20.2" @@ -2098,6 +2359,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-arm64@npm:0.19.12" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/android-arm64@npm:0.20.2" @@ -2105,6 +2373,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-arm@npm:0.19.12" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/android-arm@npm:0.20.2" @@ -2112,6 +2387,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-x64@npm:0.19.12" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/android-x64@npm:0.20.2" @@ -2119,6 +2401,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/darwin-arm64@npm:0.19.12" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/darwin-arm64@npm:0.20.2" @@ -2126,6 +2415,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/darwin-x64@npm:0.19.12" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/darwin-x64@npm:0.20.2" @@ -2133,6 +2429,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/freebsd-arm64@npm:0.19.12" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/freebsd-arm64@npm:0.20.2" @@ -2140,6 +2443,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/freebsd-x64@npm:0.19.12" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/freebsd-x64@npm:0.20.2" @@ -2147,6 +2457,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-arm64@npm:0.19.12" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-arm64@npm:0.20.2" @@ -2154,6 +2471,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-arm@npm:0.19.12" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-arm@npm:0.20.2" @@ -2161,6 +2485,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-ia32@npm:0.19.12" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-ia32@npm:0.20.2" @@ -2168,6 +2499,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-loong64@npm:0.19.12" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-loong64@npm:0.20.2" @@ -2175,6 +2513,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-mips64el@npm:0.19.12" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-mips64el@npm:0.20.2" @@ -2182,6 +2527,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-ppc64@npm:0.19.12" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-ppc64@npm:0.20.2" @@ -2189,6 +2541,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-riscv64@npm:0.19.12" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-riscv64@npm:0.20.2" @@ -2196,6 +2555,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-s390x@npm:0.19.12" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-s390x@npm:0.20.2" @@ -2203,6 +2569,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-x64@npm:0.19.12" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/linux-x64@npm:0.20.2" @@ -2210,6 +2583,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/netbsd-x64@npm:0.19.12" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/netbsd-x64@npm:0.20.2" @@ -2217,6 +2597,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/openbsd-x64@npm:0.19.12" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/openbsd-x64@npm:0.20.2" @@ -2224,6 +2611,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/sunos-x64@npm:0.19.12" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/sunos-x64@npm:0.20.2" @@ -2231,6 +2625,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-arm64@npm:0.19.12" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/win32-arm64@npm:0.20.2" @@ -2238,6 +2639,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-ia32@npm:0.19.12" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/win32-ia32@npm:0.20.2" @@ -2245,6 +2653,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-x64@npm:0.19.12" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.20.2": version: 0.20.2 resolution: "@esbuild/win32-x64@npm:0.20.2" @@ -2446,7 +2861,9 @@ __metadata: "@nx/jest": "npm:18.3.3" "@nx/js": "npm:18.3.3" "@nx/next": "npm:18.3.3" + "@nx/react": "npm:18.3.3" "@nx/rollup": "npm:18.3.3" + "@nx/vite": "npm:18.3.3" "@nx/web": "npm:18.3.3" "@nx/workspace": "npm:18.3.3" "@recoiljs/refine": "npm:^0.1.1" @@ -2459,6 +2876,7 @@ __metadata: "@swc/core": "npm:~1.3.85" "@swc/helpers": "npm:~0.5.2" "@tanstack/react-query": "npm:^4.36.1" + "@testing-library/react": "npm:14.0.0" "@tippyjs/react": "npm:^4.2.6" "@tmcw/togeojson": "npm:^5.8.1" "@turf/bbox": "npm:6.5.0" @@ -2501,6 +2919,9 @@ __metadata: "@typescript-eslint/eslint-plugin": "npm:7.6.0" "@typescript-eslint/parser": "npm:7.6.0" "@typescript-eslint/scope-manager": "npm:7.0.1" + "@vitejs/plugin-react": "npm:^4.2.0" + "@vitest/coverage-v8": "npm:^1.0.4" + "@vitest/ui": "npm:^1.3.1" abortcontroller-polyfill: "npm:^1.7.5" apache-arrow: "npm:^15.0.0" array.prototype.flatmap: "npm:1.3.2" @@ -2553,6 +2974,7 @@ __metadata: jest: "npm:^29.4.1" jest-environment-jsdom: "npm:^29.4.1" jotai: "npm:^2.6.4" + jsdom: "npm:~22.1.0" json2csv: "npm:^6.0.0-alpha.2" jszip: "npm:^3.10.1" lint-staged: "npm:^15.2.2" @@ -2589,6 +3011,7 @@ __metadata: react-query: "npm:^3.39.3" react-range: "npm:^1.8.14" react-redux: "npm:^9.1.0" + react-router-dom: "npm:6.11.2" react-spring: "npm:^9.7.3" react-sticky-el: "npm:2.1.0" react-virtualized-auto-sizer: "npm:^1.0.20" @@ -2613,6 +3036,9 @@ __metadata: typescript: "npm:5.4.5" use-debounce: "npm:^10.0.0" usehooks-ts: "npm:^2.14.0" + vite: "npm:~5.0.0" + vite-plugin-static-copy: "npm:^1.0.5" + vitest: "npm:^1.3.1" web-vitals: "npm:^3.5.1" languageName: unknown linkType: soft @@ -2966,7 +3392,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: 10/89960ac087781b961ad918978975bcdf2051cd1741880469783c42de64239703eab9db5230d776d8e6a09d73bb5e4cb964e07d93ee6e2e7aea5a7d726e865c09 @@ -2983,7 +3409,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: @@ -4180,6 +4606,15 @@ __metadata: languageName: node linkType: hard +"@nrwl/vite@npm:18.3.3": + version: 18.3.3 + resolution: "@nrwl/vite@npm:18.3.3" + dependencies: + "@nx/vite": "npm:18.3.3" + checksum: 10/e716582574c7c6fae549cf226dce95717ff7590b1f6947ca8a184935aa30964efeec500d3f4684851031d070041ea1ede998dd7456721ed98b0029c780c44790 + languageName: node + linkType: hard + "@nrwl/web@npm:18.3.3": version: 18.3.3 resolution: "@nrwl/web@npm:18.3.3" @@ -4528,6 +4963,24 @@ __metadata: languageName: node linkType: hard +"@nx/vite@npm:18.3.3": + version: 18.3.3 + resolution: "@nx/vite@npm:18.3.3" + dependencies: + "@nrwl/vite": "npm:18.3.3" + "@nx/devkit": "npm:18.3.3" + "@nx/js": "npm:18.3.3" + "@phenomnomnominal/tsquery": "npm:~5.0.1" + "@swc/helpers": "npm:~0.5.0" + enquirer: "npm:~2.3.6" + tsconfig-paths: "npm:^4.1.2" + peerDependencies: + vite: ^5.0.0 + vitest: ^1.3.1 + checksum: 10/0babe31911632698eeca8a615f86c52f92e6de74eabf23c1b4d98db591f6a9d92d18a7c6787f59a65f9f25894e62dd65e967f4792e049e9ed013cd7ec6958e03 + languageName: node + linkType: hard + "@nx/web@npm:18.3.3": version: 18.3.3 resolution: "@nx/web@npm:18.3.3" @@ -4908,6 +5361,13 @@ __metadata: languageName: node linkType: hard +"@remix-run/router@npm:1.6.2": + version: 1.6.2 + resolution: "@remix-run/router@npm:1.6.2" + checksum: 10/c261c3b52f08d7fcacce9c66d68dba3b6f0c8263ea15f69f9f1c89734685cdfe4f383c879324acade68cb331d48e3deca9ec00734abe08d9694e529096907f40 + languageName: node + linkType: hard + "@researchgate/react-intersection-observer@npm:1.3.5": version: 1.3.5 resolution: "@researchgate/react-intersection-observer@npm:1.3.5" @@ -5072,6 +5532,118 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm-eabi@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.18.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-android-arm64@npm:4.18.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.18.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.18.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.18.0" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.18.0" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.18.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.18.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.18.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.18.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.18.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.18.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.18.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.18.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.18.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.18.0": + version: 4.18.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.18.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rushstack/eslint-patch@npm:^1.1.0, @rushstack/eslint-patch@npm:^1.3.3": version: 1.10.2 resolution: "@rushstack/eslint-patch@npm:1.10.2" @@ -5510,7 +6082,16 @@ __metadata: resolution: "@swc/helpers@npm:0.5.10" dependencies: tslib: "npm:^2.4.0" - checksum: 10/840a1bbac06bfebbca1bd02a63610ee6a72e170ad9f156936d20220385624a88d900d5a668a1d0bcac57776a0aaa26a97c2503a796624a05764957a2322cc5b2 + checksum: 10/840a1bbac06bfebbca1bd02a63610ee6a72e170ad9f156936d20220385624a88d900d5a668a1d0bcac57776a0aaa26a97c2503a796624a05764957a2322cc5b2 + languageName: node + linkType: hard + +"@swc/helpers@npm:~0.5.0": + version: 0.5.11 + resolution: "@swc/helpers@npm:0.5.11" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10/54d66ade8010e6ba526a9d73b8bcdbb01c806a24f2d3786640ef3081065e8fba398d9b890df4847744c33d086412fd9a6570b5e99e8001ea1462efc5ce0f3847 languageName: node linkType: hard @@ -5605,6 +6186,36 @@ __metadata: languageName: node linkType: hard +"@testing-library/dom@npm:^9.0.0": + version: 9.3.4 + resolution: "@testing-library/dom@npm:9.3.4" + dependencies: + "@babel/code-frame": "npm:^7.10.4" + "@babel/runtime": "npm:^7.12.5" + "@types/aria-query": "npm:^5.0.1" + aria-query: "npm:5.1.3" + chalk: "npm:^4.1.0" + dom-accessibility-api: "npm:^0.5.9" + lz-string: "npm:^1.5.0" + pretty-format: "npm:^27.0.2" + checksum: 10/510da752ea76f4a10a0a4e3a77917b0302cf03effe576cd3534cab7e796533ee2b0e9fb6fb11b911a1ebd7c70a0bb6f235bf4f816c9b82b95b8fe0cddfd10975 + languageName: node + linkType: hard + +"@testing-library/react@npm:14.0.0": + version: 14.0.0 + resolution: "@testing-library/react@npm:14.0.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + "@testing-library/dom": "npm:^9.0.0" + "@types/react-dom": "npm:^18.0.0" + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + checksum: 10/1f2a4f78d107e741b35671e9c7dd992d5c9f49b48ee24112ccfe636179be72f3c62a65b1405901b59eb6cde996176ebc2c99099e04d9f14575641e46688747f0 + languageName: node + linkType: hard + "@tippyjs/react@npm:^4.2.6": version: 4.2.6 resolution: "@tippyjs/react@npm:4.2.6" @@ -7083,7 +7694,14 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14": +"@types/aria-query@npm:^5.0.1": + version: 5.0.4 + resolution: "@types/aria-query@npm:5.0.4" + checksum: 10/c0084c389dc030daeaf0115a92ce43a3f4d42fc8fef2d0e22112d87a42798d4a15aac413019d4a63f868327d52ad6740ab99609462b442fe6b9286b172d2e82e + languageName: node + linkType: hard + +"@types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.20.5": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: @@ -7490,7 +8108,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5": +"@types/estree@npm:*, @types/estree@npm:1.0.5, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5": version: 1.0.5 resolution: "@types/estree@npm:1.0.5" checksum: 10/7de6d928dd4010b0e20c6919e1a6c27b61f8d4567befa89252055fad503d587ecb9a1e3eab1b1901f923964d7019796db810b7fd6430acb26c32866d126fd408 @@ -8484,6 +9102,115 @@ __metadata: languageName: node linkType: hard +"@vitejs/plugin-react@npm:^4.2.0": + version: 4.3.0 + resolution: "@vitejs/plugin-react@npm:4.3.0" + dependencies: + "@babel/core": "npm:^7.24.5" + "@babel/plugin-transform-react-jsx-self": "npm:^7.24.5" + "@babel/plugin-transform-react-jsx-source": "npm:^7.24.1" + "@types/babel__core": "npm:^7.20.5" + react-refresh: "npm:^0.14.2" + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + checksum: 10/b96cfcfef10a7bb9a27cc4678c3828acd05522ce31793679d414300f29902f55d6dd88054e5801b5e67c34817a610a7fcb350a4896ac719320777653c98ca7a9 + languageName: node + linkType: hard + +"@vitest/coverage-v8@npm:^1.0.4": + version: 1.6.0 + resolution: "@vitest/coverage-v8@npm:1.6.0" + dependencies: + "@ampproject/remapping": "npm:^2.2.1" + "@bcoe/v8-coverage": "npm:^0.2.3" + debug: "npm:^4.3.4" + istanbul-lib-coverage: "npm:^3.2.2" + istanbul-lib-report: "npm:^3.0.1" + istanbul-lib-source-maps: "npm:^5.0.4" + istanbul-reports: "npm:^3.1.6" + magic-string: "npm:^0.30.5" + magicast: "npm:^0.3.3" + picocolors: "npm:^1.0.0" + std-env: "npm:^3.5.0" + strip-literal: "npm:^2.0.0" + test-exclude: "npm:^6.0.0" + peerDependencies: + vitest: 1.6.0 + checksum: 10/705d5f40c7795c9aa5123cca937760f060209241911dae63bd6db2f03b59f3ca41661b6a691bb781509312228cf91b4669a4daf7170a7ba7d5b6f5161a999443 + languageName: node + linkType: hard + +"@vitest/expect@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/expect@npm:1.6.0" + dependencies: + "@vitest/spy": "npm:1.6.0" + "@vitest/utils": "npm:1.6.0" + chai: "npm:^4.3.10" + checksum: 10/e82304a12e22b98c1ccea81e8f33c838561deb878588eac463164cc4f8fc0c401ace3a9e6758d9e3a6bcc01313e845e8478aaefb7548eaded04b8de12c1928f6 + languageName: node + linkType: hard + +"@vitest/runner@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/runner@npm:1.6.0" + dependencies: + "@vitest/utils": "npm:1.6.0" + p-limit: "npm:^5.0.0" + pathe: "npm:^1.1.1" + checksum: 10/d83a608be36dace77f91a9d15ab7753f9c5923281188a8d9cb5ccec770df9cc9ba80e5e1e3465328c7605977be0f0708610855abf5f4af037a4ede5f51a83e47 + languageName: node + linkType: hard + +"@vitest/snapshot@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/snapshot@npm:1.6.0" + dependencies: + magic-string: "npm:^0.30.5" + pathe: "npm:^1.1.1" + pretty-format: "npm:^29.7.0" + checksum: 10/0bfc26a48b45814604ff0f7276d73a047b79f3618e0b620ff54ea2de548e9603a9770963ba6ebb19f7ea1ed51001cbca58d74aa0271651d4f8e88c6233885eba + languageName: node + linkType: hard + +"@vitest/spy@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/spy@npm:1.6.0" + dependencies: + tinyspy: "npm:^2.2.0" + checksum: 10/1c9698272a58aa47708bb8a1672d655fcec3285b02067cc3f70bfe76f4eda7a756eb379f8c945ccbe61677f5189aeb5ba93c2737a9d7db2de8c4e7bbdffcd372 + languageName: node + linkType: hard + +"@vitest/ui@npm:^1.3.1": + version: 1.6.0 + resolution: "@vitest/ui@npm:1.6.0" + dependencies: + "@vitest/utils": "npm:1.6.0" + fast-glob: "npm:^3.3.2" + fflate: "npm:^0.8.1" + flatted: "npm:^3.2.9" + pathe: "npm:^1.1.1" + picocolors: "npm:^1.0.0" + sirv: "npm:^2.0.4" + peerDependencies: + vitest: 1.6.0 + checksum: 10/4927285e1aaf1aec449055ad86be424ea8db513e8904c425226203fe14480850061213afd638929e17f9817d18c1e935215f50c0a4f7d885c15b6aefc80ca358 + languageName: node + linkType: hard + +"@vitest/utils@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/utils@npm:1.6.0" + dependencies: + diff-sequences: "npm:^29.6.3" + estree-walker: "npm:^3.0.3" + loupe: "npm:^2.3.7" + pretty-format: "npm:^29.7.0" + checksum: 10/5c5d7295ac13fcea1da039232bcc7c3fc6f070070fe12ba2ad152456af6e216e48a3ae169016cfcd5055706a00dc567b8f62e4a9b1914f069f52b8f0a3c25e60 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.12.1, @webassemblyjs/ast@npm:^1.12.1": version: 1.12.1 resolution: "@webassemblyjs/ast@npm:1.12.1" @@ -8748,14 +9475,14 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1": +"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.3.2": version: 8.3.2 resolution: "acorn-walk@npm:8.3.2" checksum: 10/57dbe2fd8cf744f562431775741c5c087196cd7a65ce4ccb3f3981cdfad25cd24ad2bad404997b88464ac01e789a0a61e5e355b2a84876f13deef39fb39686ca languageName: node linkType: hard -"acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.8.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": +"acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.11.3, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.8.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": version: 8.11.3 resolution: "acorn@npm:8.11.3" bin: @@ -9015,6 +9742,15 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:5.1.3": + version: 5.1.3 + resolution: "aria-query@npm:5.1.3" + dependencies: + deep-equal: "npm:^2.0.5" + checksum: 10/e5da608a7c4954bfece2d879342b6c218b6b207e2d9e5af270b5e38ef8418f02d122afdc948b68e32649b849a38377785252059090d66fa8081da95d1609c0d2 + languageName: node + linkType: hard + "aria-query@npm:^5.3.0": version: 5.3.0 resolution: "aria-query@npm:5.3.0" @@ -9045,7 +9781,7 @@ __metadata: languageName: node linkType: hard -"array-buffer-byte-length@npm:^1.0.1": +"array-buffer-byte-length@npm:^1.0.0, array-buffer-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "array-buffer-byte-length@npm:1.0.1" dependencies: @@ -9222,6 +9958,13 @@ __metadata: languageName: node linkType: hard +"assertion-error@npm:^1.1.0": + version: 1.1.0 + resolution: "assertion-error@npm:1.1.0" + checksum: 10/fd9429d3a3d4fd61782eb3962ae76b6d08aa7383123fca0596020013b3ebd6647891a85b05ce821c47d1471ed1271f00b0545cf6a4326cf2fc91efcc3b0fbecf + languageName: node + linkType: hard + "assign-symbols@npm:^1.0.0": version: 1.0.0 resolution: "assign-symbols@npm:1.0.0" @@ -10043,6 +10786,13 @@ __metadata: languageName: node linkType: hard +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 10/002769a0fbfc51c062acd2a59df465a2a947916b02ac50b56c69ec6c018ee99ac3e7f4dd7366334ea847f1ecacf4defaa61bcd2ac283db50156ce1f1d8c8ad42 + languageName: node + linkType: hard + "cacache@npm:^18.0.0": version: 18.0.2 resolution: "cacache@npm:18.0.2" @@ -10152,6 +10902,21 @@ __metadata: languageName: node linkType: hard +"chai@npm:^4.3.10": + version: 4.4.1 + resolution: "chai@npm:4.4.1" + dependencies: + assertion-error: "npm:^1.1.0" + check-error: "npm:^1.0.3" + deep-eql: "npm:^4.1.3" + get-func-name: "npm:^2.0.2" + loupe: "npm:^2.3.6" + pathval: "npm:^1.1.1" + type-detect: "npm:^4.0.8" + checksum: 10/c6d7aba913a67529c68dbec3673f94eb9c586c5474cc5142bd0b587c9c9ec9e5fbaa937e038ecaa6475aea31433752d5fabdd033b9248bde6ae53befcde774ae + languageName: node + linkType: hard + "chalk-template@npm:^0.4.0": version: 0.4.0 resolution: "chalk-template@npm:0.4.0" @@ -10216,6 +10981,15 @@ __metadata: languageName: node linkType: hard +"check-error@npm:^1.0.3": + version: 1.0.3 + resolution: "check-error@npm:1.0.3" + dependencies: + get-func-name: "npm:^2.0.2" + checksum: 10/e2131025cf059b21080f4813e55b3c480419256914601750b0fee3bd9b2b8315b531e551ef12560419b8b6d92a3636511322752b1ce905703239e7cc451b6399 + languageName: node + linkType: hard + "check-more-types@npm:^2.24.0": version: 2.24.0 resolution: "check-more-types@npm:2.24.0" @@ -10724,6 +11498,13 @@ __metadata: languageName: node linkType: hard +"confbox@npm:^0.1.7": + version: 0.1.7 + resolution: "confbox@npm:0.1.7" + checksum: 10/3086687b9a2a70d44d4b40a2d376536fe7e1baec4a2a34261b21b8a836026b419cbf89ded6054216631823e7d63c415dad4b4d53591d6edbb202bb9820dfa6fa + languageName: node + linkType: hard + "confusing-browser-globals@npm:^1.0.11, confusing-browser-globals@npm:^1.0.9": version: 1.0.11 resolution: "confusing-browser-globals@npm:1.0.11" @@ -11475,6 +12256,15 @@ __metadata: languageName: node linkType: hard +"cssstyle@npm:^3.0.0": + version: 3.0.0 + resolution: "cssstyle@npm:3.0.0" + dependencies: + rrweb-cssom: "npm:^0.6.0" + checksum: 10/3774cf5fd0fe5d0fe2d7e2b726eea690e7e35a2f3ecdd83bcf2df12ad664bc6cc30727800b712c16b5df6a67e5129a643fe15c0bfb1fc221d0020c488b1f4ff3 + languageName: node + linkType: hard + "csstype@npm:^3.0.2, csstype@npm:^3.1.3": version: 3.1.3 resolution: "csstype@npm:3.1.3" @@ -11909,6 +12699,17 @@ __metadata: languageName: node linkType: hard +"data-urls@npm:^4.0.0": + version: 4.0.0 + resolution: "data-urls@npm:4.0.0" + dependencies: + abab: "npm:^2.0.6" + whatwg-mimetype: "npm:^3.0.0" + whatwg-url: "npm:^12.0.0" + checksum: 10/006e869b5bf079647949a3e9b1dd69d84b2d5d26e6b01c265485699bc96e83817d4b5aae758b2910a4c58c0601913f3a0034121c1ca2da268e9a244c57515b15 + languageName: node + linkType: hard + "data-view-buffer@npm:^1.0.1": version: 1.0.1 resolution: "data-view-buffer@npm:1.0.1" @@ -12007,7 +12808,7 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:^10.4.2": +"decimal.js@npm:^10.4.2, decimal.js@npm:^10.4.3": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" checksum: 10/de663a7bc4d368e3877db95fcd5c87b965569b58d16cdc4258c063d231ca7118748738df17cd638f7e9dd0be8e34cec08d7234b20f1f2a756a52fc5a38b188d0 @@ -12098,6 +12899,15 @@ __metadata: languageName: node linkType: hard +"deep-eql@npm:^4.1.3": + version: 4.1.3 + resolution: "deep-eql@npm:4.1.3" + dependencies: + type-detect: "npm:^4.0.0" + checksum: 10/12ce93ae63de187e77b076d3d51bfc28b11f98910a22c18714cce112791195e86a94f97788180994614b14562a86c9763f67c69f785e4586f806b5df39bf9301 + languageName: node + linkType: hard + "deep-equal@npm:1.x, deep-equal@npm:^1.0.0": version: 1.1.2 resolution: "deep-equal@npm:1.1.2" @@ -12112,6 +12922,32 @@ __metadata: languageName: node linkType: hard +"deep-equal@npm:^2.0.5": + version: 2.2.3 + resolution: "deep-equal@npm:2.2.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.0" + call-bind: "npm:^1.0.5" + es-get-iterator: "npm:^1.1.3" + get-intrinsic: "npm:^1.2.2" + is-arguments: "npm:^1.1.1" + is-array-buffer: "npm:^3.0.2" + is-date-object: "npm:^1.0.5" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.2" + isarray: "npm:^2.0.5" + object-is: "npm:^1.1.5" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.4" + regexp.prototype.flags: "npm:^1.5.1" + side-channel: "npm:^1.0.4" + which-boxed-primitive: "npm:^1.0.2" + which-collection: "npm:^1.0.1" + which-typed-array: "npm:^1.1.13" + checksum: 10/1ce49d0b71d0f14d8ef991a742665eccd488dfc9b3cada069d4d7a86291e591c92d2589c832811dea182b4015736b210acaaebce6184be356c1060d176f5a05f + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -12362,6 +13198,13 @@ __metadata: languageName: node linkType: hard +"dom-accessibility-api@npm:^0.5.9": + version: 0.5.16 + resolution: "dom-accessibility-api@npm:0.5.16" + checksum: 10/377b4a7f9eae0a5d72e1068c369c99e0e4ca17fdfd5219f3abd32a73a590749a267475a59d7b03a891f9b673c27429133a818c44b2e47e32fec024b34274e2ca + languageName: node + linkType: hard + "dom-helpers@npm:^3.4.0": version: 3.4.0 resolution: "dom-helpers@npm:3.4.0" @@ -12800,6 +13643,23 @@ __metadata: languageName: node linkType: hard +"es-get-iterator@npm:^1.1.3": + version: 1.1.3 + resolution: "es-get-iterator@npm:1.1.3" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.1.3" + has-symbols: "npm:^1.0.3" + is-arguments: "npm:^1.1.1" + is-map: "npm:^2.0.2" + is-set: "npm:^2.0.2" + is-string: "npm:^1.0.7" + isarray: "npm:^2.0.5" + stop-iteration-iterator: "npm:^1.0.0" + checksum: 10/bc2194befbe55725f9489098626479deee3c801eda7e83ce0dff2eb266a28dc808edb9b623ff01d31ebc1328f09d661333d86b601036692c2e3c1a6942319433 + languageName: node + linkType: hard + "es-iterator-helpers@npm:^1.0.15, es-iterator-helpers@npm:^1.0.17": version: 1.0.18 resolution: "es-iterator-helpers@npm:1.0.18" @@ -12869,6 +13729,86 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.19.3": + version: 0.19.12 + resolution: "esbuild@npm:0.19.12" + dependencies: + "@esbuild/aix-ppc64": "npm:0.19.12" + "@esbuild/android-arm": "npm:0.19.12" + "@esbuild/android-arm64": "npm:0.19.12" + "@esbuild/android-x64": "npm:0.19.12" + "@esbuild/darwin-arm64": "npm:0.19.12" + "@esbuild/darwin-x64": "npm:0.19.12" + "@esbuild/freebsd-arm64": "npm:0.19.12" + "@esbuild/freebsd-x64": "npm:0.19.12" + "@esbuild/linux-arm": "npm:0.19.12" + "@esbuild/linux-arm64": "npm:0.19.12" + "@esbuild/linux-ia32": "npm:0.19.12" + "@esbuild/linux-loong64": "npm:0.19.12" + "@esbuild/linux-mips64el": "npm:0.19.12" + "@esbuild/linux-ppc64": "npm:0.19.12" + "@esbuild/linux-riscv64": "npm:0.19.12" + "@esbuild/linux-s390x": "npm:0.19.12" + "@esbuild/linux-x64": "npm:0.19.12" + "@esbuild/netbsd-x64": "npm:0.19.12" + "@esbuild/openbsd-x64": "npm:0.19.12" + "@esbuild/sunos-x64": "npm:0.19.12" + "@esbuild/win32-arm64": "npm:0.19.12" + "@esbuild/win32-ia32": "npm:0.19.12" + "@esbuild/win32-x64": "npm:0.19.12" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10/861fa8eb2428e8d6521a4b7c7930139e3f45e8d51a86985cc29408172a41f6b18df7b3401e7e5e2d528cdf83742da601ddfdc77043ddc4f1c715a8ddb2d8a255 + languageName: node + linkType: hard + "esbuild@npm:^0.20.1, esbuild@npm:^0.20.2": version: 0.20.2 resolution: "esbuild@npm:0.20.2" @@ -13416,6 +14356,15 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10/a65728d5727b71de172c5df323385755a16c0fdab8234dc756c3854cfee343261ddfbb72a809a5660fac8c75d960bb3e21aa898c2d7e9b19bb298482ca58a3af + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -13475,7 +14424,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:8.0.1": +"execa@npm:8.0.1, execa@npm:^8.0.1": version: 8.0.1 resolution: "execa@npm:8.0.1" dependencies: @@ -13727,7 +14676,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.5, fast-glob@npm:^3.2.7, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.1, fast-glob@npm:^3.3.2": +"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.5, fast-glob@npm:^3.2.7, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.1, fast-glob@npm:^3.3.2": version: 3.3.2 resolution: "fast-glob@npm:3.3.2" dependencies: @@ -13808,6 +14757,13 @@ __metadata: languageName: node linkType: hard +"fflate@npm:^0.8.1": + version: 0.8.2 + resolution: "fflate@npm:0.8.2" + checksum: 10/2bd26ba6d235d428de793c6a0cd1aaa96a06269ebd4e21b46c8fd1bd136abc631acf27e188d47c3936db090bf3e1ede11d15ce9eae9bffdc4bfe1b9dc66ca9cb + languageName: node + linkType: hard + "figures@npm:3.2.0, figures@npm:^3.0.0, figures@npm:^3.2.0": version: 3.2.0 resolution: "figures@npm:3.2.0" @@ -14299,7 +15255,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": +"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -14309,7 +15265,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": +"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -14454,7 +15410,14 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": +"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2": + version: 2.0.2 + resolution: "get-func-name@npm:2.0.2" + checksum: 10/3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" dependencies: @@ -15686,7 +16649,7 @@ __metadata: languageName: node linkType: hard -"internal-slot@npm:^1.0.7": +"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" dependencies: @@ -15754,7 +16717,7 @@ __metadata: languageName: node linkType: hard -"is-array-buffer@npm:^3.0.4": +"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4": version: 3.0.4 resolution: "is-array-buffer@npm:3.0.4" dependencies: @@ -15982,7 +16945,7 @@ __metadata: languageName: node linkType: hard -"is-map@npm:^2.0.3": +"is-map@npm:^2.0.2, is-map@npm:^2.0.3": version: 2.0.3 resolution: "is-map@npm:2.0.3" checksum: 10/8de7b41715b08bcb0e5edb0fb9384b80d2d5bcd10e142188f33247d19ff078abaf8e9b6f858e2302d8d05376a26a55cd23a3c9f8ab93292b02fcd2cc9e4e92bb @@ -16156,7 +17119,7 @@ __metadata: languageName: node linkType: hard -"is-set@npm:^2.0.3": +"is-set@npm:^2.0.2, is-set@npm:^2.0.3": version: 2.0.3 resolution: "is-set@npm:2.0.3" checksum: 10/5685df33f0a4a6098a98c72d94d67cad81b2bc72f1fb2091f3d9283c4a1c582123cd709145b02a9745f0ce6b41e3e43f1c944496d1d74d4ea43358be61308669 @@ -16341,7 +17304,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": +"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0, istanbul-lib-coverage@npm:^3.2.2": version: 3.2.2 resolution: "istanbul-lib-coverage@npm:3.2.2" checksum: 10/40bbdd1e937dfd8c830fa286d0f665e81b7a78bdabcd4565f6d5667c99828bda3db7fb7ac6b96a3e2e8a2461ddbc5452d9f8bc7d00cb00075fa6a3e99f5b6a81 @@ -16374,7 +17337,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-report@npm:^3.0.0": +"istanbul-lib-report@npm:^3.0.0, istanbul-lib-report@npm:^3.0.1": version: 3.0.1 resolution: "istanbul-lib-report@npm:3.0.1" dependencies: @@ -16396,7 +17359,18 @@ __metadata: languageName: node linkType: hard -"istanbul-reports@npm:^3.1.3": +"istanbul-lib-source-maps@npm:^5.0.4": + version: 5.0.4 + resolution: "istanbul-lib-source-maps@npm:5.0.4" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.23" + debug: "npm:^4.1.1" + istanbul-lib-coverage: "npm:^3.0.0" + checksum: 10/e6f9fedab9c047d0ca1e58bf1697c3d7478e77271e5cd55b01e425dcdfc99534f54c6dfb981d5746e9a69b2697009f907d4c4f02f4000d66f22164a7610e6aa2 + languageName: node + linkType: hard + +"istanbul-reports@npm:^3.1.3, istanbul-reports@npm:^3.1.6": version: 3.1.7 resolution: "istanbul-reports@npm:3.1.7" dependencies: @@ -16957,6 +17931,13 @@ __metadata: languageName: node linkType: hard +"js-tokens@npm:^9.0.0": + version: 9.0.0 + resolution: "js-tokens@npm:9.0.0" + checksum: 10/65e7a55a1a18d61f1cf94bfd7704da870b74337fa08d4c58118e69a8b10225b5ad887ff3ae595d720301b0924811a9b0594c679621a85ecbac6e3aac8533c53b + languageName: node + linkType: hard + "js-yaml@npm:4.1.0, js-yaml@npm:^4.1.0": version: 4.1.0 resolution: "js-yaml@npm:4.1.0" @@ -16994,26 +17975,62 @@ __metadata: languageName: node linkType: hard -"jsdom@npm:^20.0.0": - version: 20.0.3 - resolution: "jsdom@npm:20.0.3" +"jsdom@npm:^20.0.0": + version: 20.0.3 + resolution: "jsdom@npm:20.0.3" + dependencies: + abab: "npm:^2.0.6" + acorn: "npm:^8.8.1" + acorn-globals: "npm:^7.0.0" + cssom: "npm:^0.5.0" + cssstyle: "npm:^2.3.0" + data-urls: "npm:^3.0.2" + decimal.js: "npm:^10.4.2" + domexception: "npm:^4.0.0" + escodegen: "npm:^2.0.0" + form-data: "npm:^4.0.0" + html-encoding-sniffer: "npm:^3.0.0" + http-proxy-agent: "npm:^5.0.0" + https-proxy-agent: "npm:^5.0.1" + is-potential-custom-element-name: "npm:^1.0.1" + nwsapi: "npm:^2.2.2" + parse5: "npm:^7.1.1" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^4.1.2" + w3c-xmlserializer: "npm:^4.0.0" + webidl-conversions: "npm:^7.0.0" + whatwg-encoding: "npm:^2.0.0" + whatwg-mimetype: "npm:^3.0.0" + whatwg-url: "npm:^11.0.0" + ws: "npm:^8.11.0" + xml-name-validator: "npm:^4.0.0" + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + checksum: 10/a4cdcff5b07eed87da90b146b82936321533b5efe8124492acf7160ebd5b9cf2b3c2435683592bf1cffb479615245756efb6c173effc1906f845a86ed22af985 + languageName: node + linkType: hard + +"jsdom@npm:~22.1.0": + version: 22.1.0 + resolution: "jsdom@npm:22.1.0" dependencies: abab: "npm:^2.0.6" - acorn: "npm:^8.8.1" - acorn-globals: "npm:^7.0.0" - cssom: "npm:^0.5.0" - cssstyle: "npm:^2.3.0" - data-urls: "npm:^3.0.2" - decimal.js: "npm:^10.4.2" + cssstyle: "npm:^3.0.0" + data-urls: "npm:^4.0.0" + decimal.js: "npm:^10.4.3" domexception: "npm:^4.0.0" - escodegen: "npm:^2.0.0" form-data: "npm:^4.0.0" html-encoding-sniffer: "npm:^3.0.0" http-proxy-agent: "npm:^5.0.0" https-proxy-agent: "npm:^5.0.1" is-potential-custom-element-name: "npm:^1.0.1" - nwsapi: "npm:^2.2.2" - parse5: "npm:^7.1.1" + nwsapi: "npm:^2.2.4" + parse5: "npm:^7.1.2" + rrweb-cssom: "npm:^0.6.0" saxes: "npm:^6.0.0" symbol-tree: "npm:^3.2.4" tough-cookie: "npm:^4.1.2" @@ -17021,15 +18038,15 @@ __metadata: webidl-conversions: "npm:^7.0.0" whatwg-encoding: "npm:^2.0.0" whatwg-mimetype: "npm:^3.0.0" - whatwg-url: "npm:^11.0.0" - ws: "npm:^8.11.0" + whatwg-url: "npm:^12.0.1" + ws: "npm:^8.13.0" xml-name-validator: "npm:^4.0.0" peerDependencies: canvas: ^2.5.0 peerDependenciesMeta: canvas: optional: true - checksum: 10/a4cdcff5b07eed87da90b146b82936321533b5efe8124492acf7160ebd5b9cf2b3c2435683592bf1cffb479615245756efb6c173effc1906f845a86ed22af985 + checksum: 10/dd36103db638c7720a446375bb70fc410ee74881881824cde6dba7e2b387167d1299ffbc9699fc623dfe9a2b69c6da66e920cf847c7fbf96a78e6b39a60fcf4f languageName: node linkType: hard @@ -17599,6 +18616,16 @@ __metadata: languageName: node linkType: hard +"local-pkg@npm:^0.5.0": + version: 0.5.0 + resolution: "local-pkg@npm:0.5.0" + dependencies: + mlly: "npm:^1.4.2" + pkg-types: "npm:^1.0.3" + checksum: 10/20f4caba50dc6fb00ffcc1a78bc94b5acb33995e0aadf4d4edcdeab257e891aa08f50afddf02f3240b2c3d02432bc2078f2a916a280ed716b64753a3d250db70 + languageName: node + linkType: hard + "locate-path@npm:^5.0.0": version: 5.0.0 resolution: "locate-path@npm:5.0.0" @@ -17815,6 +18842,15 @@ __metadata: languageName: node linkType: hard +"loupe@npm:^2.3.6, loupe@npm:^2.3.7": + version: 2.3.7 + resolution: "loupe@npm:2.3.7" + dependencies: + get-func-name: "npm:^2.0.1" + checksum: 10/635c8f0914c2ce7ecfe4e239fbaf0ce1d2c00e4246fafcc4ed000bfdb1b8f89d05db1a220054175cca631ebf3894872a26fffba0124477fcb562f78762848fb1 + languageName: node + linkType: hard + "lower-case@npm:^2.0.2": version: 2.0.2 resolution: "lower-case@npm:2.0.2" @@ -17880,6 +18916,15 @@ __metadata: languageName: node linkType: hard +"lz-string@npm:^1.5.0": + version: 1.5.0 + resolution: "lz-string@npm:1.5.0" + bin: + lz-string: bin/bin.js + checksum: 10/e86f0280e99a8d8cd4eef24d8601ddae15ce54e43ac9990dfcb79e1e081c255ad24424a30d78d2ad8e51a8ce82a66a930047fed4b4aa38c6f0b392ff9300edfc + languageName: node + linkType: hard + "magic-string@npm:^0.25.0, magic-string@npm:^0.25.7": version: 0.25.9 resolution: "magic-string@npm:0.25.9" @@ -17889,6 +18934,26 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.5": + version: 0.30.10 + resolution: "magic-string@npm:0.30.10" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + checksum: 10/9f8bf6363a14c98a9d9f32ef833b194702a5c98fb931b05ac511b76f0b06fd30ed92beda6ca3261d2d52d21e39e891ef1136fbd032023f6cbb02d0b7d5767201 + languageName: node + linkType: hard + +"magicast@npm:^0.3.3": + version: 0.3.4 + resolution: "magicast@npm:0.3.4" + dependencies: + "@babel/parser": "npm:^7.24.4" + "@babel/types": "npm:^7.24.0" + source-map-js: "npm:^1.2.0" + checksum: 10/704f86639b01c8e063155408cb181d89d4444db3a4a473fb501107f30f19d9c39a159dd315ef9e54a22291c090170044efd9b49a9b3ab8d6deb948a9c99d90b3 + languageName: node + linkType: hard + "make-dir@npm:^1.0.0": version: 1.3.0 resolution: "make-dir@npm:1.3.0" @@ -18374,6 +19439,18 @@ __metadata: languageName: node linkType: hard +"mlly@npm:^1.4.2, mlly@npm:^1.7.0": + version: 1.7.0 + resolution: "mlly@npm:1.7.0" + dependencies: + acorn: "npm:^8.11.3" + pathe: "npm:^1.1.2" + pkg-types: "npm:^1.1.0" + ufo: "npm:^1.5.3" + checksum: 10/a52f17767f1aa8133ad4354065e579c3d1cc72e866102bde7e466123772f5e571327b95ce777d1d655724f0c479a82acaafc6e81e25781851779d865682c8823 + languageName: node + linkType: hard + "mochawesome-report-generator@npm:^6.2.0": version: 6.2.0 resolution: "mochawesome-report-generator@npm:6.2.0" @@ -18810,6 +19887,13 @@ __metadata: languageName: node linkType: hard +"nwsapi@npm:^2.2.4": + version: 2.2.10 + resolution: "nwsapi@npm:2.2.10" + checksum: 10/b310e9dd0886da338cbbb1be9fec473a50269e2935d537f95a03d0038f7ea831ce12b4816d97f42e458e5273158aea2a6c86bc4bb60f79911226154aa66740f7 + languageName: node + linkType: hard + "nx@npm:18.3.3": version: 18.3.3 resolution: "nx@npm:18.3.3" @@ -19191,6 +20275,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^5.0.0": + version: 5.0.0 + resolution: "p-limit@npm:5.0.0" + dependencies: + yocto-queue: "npm:^1.0.0" + checksum: 10/87bf5837dee6942f0dbeff318436179931d9a97848d1b07dbd86140a477a5d2e6b90d9701b210b4e21fe7beaea2979dfde366e4f576fa644a59bd4d6a6371da7 + languageName: node + linkType: hard + "p-locate@npm:^4.1.0": version: 4.1.0 resolution: "p-locate@npm:4.1.0" @@ -19349,7 +20442,7 @@ __metadata: languageName: node linkType: hard -"parse5@npm:^7.0.0, parse5@npm:^7.1.1": +"parse5@npm:^7.0.0, parse5@npm:^7.1.1, parse5@npm:^7.1.2": version: 7.1.2 resolution: "parse5@npm:7.1.2" dependencies: @@ -19471,6 +20564,20 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^1.1.1, pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 10/f201d796351bf7433d147b92c20eb154a4e0ea83512017bf4ec4e492a5d6e738fb45798be4259a61aa81270179fce11026f6ff0d3fa04173041de044defe9d80 + languageName: node + linkType: hard + +"pathval@npm:^1.1.1": + version: 1.1.1 + resolution: "pathval@npm:1.1.1" + checksum: 10/b50a4751068aa3a5428f5a0b480deecedc6f537666a3630a0c2ae2d5e7c0f4bf0ee77b48404441ec1220bef0c91625e6030b3d3cf5a32ab0d9764018d1d9dbb6 + languageName: node + linkType: hard + "pbf@npm:^3.2.1": version: 3.2.1 resolution: "pbf@npm:3.2.1" @@ -19596,6 +20703,17 @@ __metadata: languageName: node linkType: hard +"pkg-types@npm:^1.0.3, pkg-types@npm:^1.1.0": + version: 1.1.1 + resolution: "pkg-types@npm:1.1.1" + dependencies: + confbox: "npm:^0.1.7" + mlly: "npm:^1.7.0" + pathe: "npm:^1.1.2" + checksum: 10/225eaf7c0339027e176dd0d34a6d9a1384c21e0aab295e57dfbef1f1b7fc132f008671da7e67553e352b80b17ba38c531c720c914061d277410eef1bdd9d9608 + languageName: node + linkType: hard + "point-in-polygon@npm:^1.1.0": version: 1.1.0 resolution: "point-in-polygon@npm:1.1.0" @@ -20398,7 +21516,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.14, postcss@npm:^8.4.24, postcss@npm:^8.4.33": +"postcss@npm:^8.4.14, postcss@npm:^8.4.24, postcss@npm:^8.4.32, postcss@npm:^8.4.33, postcss@npm:^8.4.38": version: 8.4.38 resolution: "postcss@npm:8.4.38" dependencies: @@ -20476,6 +21594,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^27.0.2": + version: 27.5.1 + resolution: "pretty-format@npm:27.5.1" + dependencies: + ansi-regex: "npm:^5.0.1" + ansi-styles: "npm:^5.0.0" + react-is: "npm:^17.0.1" + checksum: 10/248990cbef9e96fb36a3e1ae6b903c551ca4ddd733f8d0912b9cc5141d3d0b3f9f8dfb4d799fb1c6723382c9c2083ffbfa4ad43ff9a0e7535d32d41fd5f01da6 + languageName: node + linkType: hard + "pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" @@ -20645,7 +21774,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1": +"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059 @@ -20861,6 +21990,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^17.0.1": + version: 17.0.2 + resolution: "react-is@npm:17.0.2" + checksum: 10/73b36281e58eeb27c9cc6031301b6ae19ecdc9f18ae2d518bdb39b0ac564e65c5779405d623f1df9abf378a13858b79442480244bd579968afc1faf9a2ce5e05 + languageName: node + linkType: hard + "react-is@npm:^18.0.0, react-is@npm:^18.2.0": version: 18.2.0 resolution: "react-is@npm:18.2.0" @@ -20959,6 +22095,37 @@ __metadata: languageName: node linkType: hard +"react-refresh@npm:^0.14.2": + version: 0.14.2 + resolution: "react-refresh@npm:0.14.2" + checksum: 10/512abf97271ab8623486061be04b608c39d932e3709f9af1720b41573415fa4993d0009fa5138b6705b60a98f4102f744d4e26c952b14f41a0e455521c6be4cc + languageName: node + linkType: hard + +"react-router-dom@npm:6.11.2": + version: 6.11.2 + resolution: "react-router-dom@npm:6.11.2" + dependencies: + "@remix-run/router": "npm:1.6.2" + react-router: "npm:6.11.2" + peerDependencies: + react: ">=16.8" + react-dom: ">=16.8" + checksum: 10/85575793cbdb84b05e9c33fef6f81e6b09e9f2606d2ba03392f83689dbb240212e5b22634b95049fc19364e9b44d45a519387d1bff4eba8a163548aa3376bc0f + languageName: node + linkType: hard + +"react-router@npm:6.11.2": + version: 6.11.2 + resolution: "react-router@npm:6.11.2" + dependencies: + "@remix-run/router": "npm:1.6.2" + peerDependencies: + react: ">=16.8" + checksum: 10/a40d1ea78e3b5b3167ed6cbaf74b2e60592fd1822b9f94a2499933bf699130a81f669bc06bdf34f38489a96d31510848c21254a48e49038b18ecbf42993eaa34 + languageName: node + linkType: hard + "react-smooth@npm:^2.0.5": version: 2.0.5 resolution: "react-smooth@npm:2.0.5" @@ -21767,6 +22934,76 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.13.0, rollup@npm:^4.2.0": + version: 4.18.0 + resolution: "rollup@npm:4.18.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.18.0" + "@rollup/rollup-android-arm64": "npm:4.18.0" + "@rollup/rollup-darwin-arm64": "npm:4.18.0" + "@rollup/rollup-darwin-x64": "npm:4.18.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.18.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.18.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.18.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.18.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.18.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.18.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.18.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.18.0" + "@rollup/rollup-linux-x64-musl": "npm:4.18.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.18.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.18.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.18.0" + "@types/estree": "npm:1.0.5" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10/2320fe653cfd5e3d72ecab2f1d52d47e7b624a6ab02919f53c1ad1c5efa3b66e277c3ecfef03bb97651e79cef04bfefd34ad1f6e648f496572bf76c834f19599 + languageName: node + linkType: hard + +"rrweb-cssom@npm:^0.6.0": + version: 0.6.0 + resolution: "rrweb-cssom@npm:0.6.0" + checksum: 10/5411836a4a78d6b68480767b8312de291f32d5710a278343954a778e5b420eaf13c90d9d2a942acf4718ddf497baa75ce653a314b332a380b6eaae1dee72257e + languageName: node + linkType: hard + "rsvp@npm:^4.8.2": version: 4.8.5 resolution: "rsvp@npm:4.8.5" @@ -22276,6 +23513,13 @@ __metadata: languageName: node linkType: hard +"siginfo@npm:^2.0.0": + version: 2.0.0 + resolution: "siginfo@npm:2.0.0" + checksum: 10/e93ff66c6531a079af8fb217240df01f980155b5dc408d2d7bebc398dd284e383eb318153bf8acd4db3c4fe799aa5b9a641e38b0ba3b1975700b1c89547ea4e7 + languageName: node + linkType: hard + "signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -22297,7 +23541,7 @@ __metadata: languageName: node linkType: hard -"sirv@npm:^2.0.3": +"sirv@npm:^2.0.3, sirv@npm:^2.0.4": version: 2.0.4 resolution: "sirv@npm:2.0.4" dependencies: @@ -22736,6 +23980,13 @@ __metadata: languageName: node linkType: hard +"stackback@npm:0.0.2": + version: 0.0.2 + resolution: "stackback@npm:0.0.2" + checksum: 10/2d4dc4e64e2db796de4a3c856d5943daccdfa3dd092e452a1ce059c81e9a9c29e0b9badba91b43ef0d5ff5c04ee62feb3bcc559a804e16faf447bac2d883aa99 + languageName: node + linkType: hard + "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -22750,6 +24001,22 @@ __metadata: languageName: node linkType: hard +"std-env@npm:^3.5.0": + version: 3.7.0 + resolution: "std-env@npm:3.7.0" + checksum: 10/6ee0cca1add3fd84656b0002cfbc5bfa20340389d9ba4720569840f1caa34bce74322aef4c93f046391583e50649d0cf81a5f8fe1d411e50b659571690a45f12 + languageName: node + linkType: hard + +"stop-iteration-iterator@npm:^1.0.0": + version: 1.0.0 + resolution: "stop-iteration-iterator@npm:1.0.0" + dependencies: + internal-slot: "npm:^1.0.4" + checksum: 10/2a23a36f4f6bfa63f46ae2d53a3f80fe8276110b95a55345d8ed3d92125413494033bc8697eb774e8f7aeb5725f70e3d69753caa2ecacdac6258c16fa8aa8b0f + languageName: node + linkType: hard + "stream-composer@npm:^1.0.2": version: 1.0.2 resolution: "stream-composer@npm:1.0.2" @@ -23019,6 +24286,15 @@ __metadata: languageName: node linkType: hard +"strip-literal@npm:^2.0.0": + version: 2.1.0 + resolution: "strip-literal@npm:2.1.0" + dependencies: + js-tokens: "npm:^9.0.0" + checksum: 10/21c813aa1e669944e7e2318c8c927939fb90b0c52f53f57282bfc3dd6e19d53f70004f1f1693e33e5e790ad5ef102b0fce2b243808229d1ce07ae71f326c0e82 + languageName: node + linkType: hard + "strip-outer@npm:^2.0.0": version: 2.0.0 resolution: "strip-outer@npm:2.0.0" @@ -23644,6 +24920,20 @@ __metadata: languageName: node linkType: hard +"tinybench@npm:^2.5.1": + version: 2.8.0 + resolution: "tinybench@npm:2.8.0" + checksum: 10/9731d070bedee6d44f3bb565862c284776e6adfd70d81a051a5c79b77479408509b448ad8d467d538d18bc0ae857b3ead8168d7e98d7f1355f8a0b01aa2f163b + languageName: node + linkType: hard + +"tinypool@npm:^0.8.3": + version: 0.8.4 + resolution: "tinypool@npm:0.8.4" + checksum: 10/7365944c2532f240111443e7012be31a634faf1a02db08a91db3aa07361c26a374d0be00a0f2ea052c4bee39c107ba67f1f814c108d9d51dfc725c559c1a9c03 + languageName: node + linkType: hard + "tinyqueue@npm:^2.0.3": version: 2.0.3 resolution: "tinyqueue@npm:2.0.3" @@ -23651,6 +24941,13 @@ __metadata: languageName: node linkType: hard +"tinyspy@npm:^2.2.0": + version: 2.2.1 + resolution: "tinyspy@npm:2.2.1" + checksum: 10/170d6232e87f9044f537b50b406a38fbfd6f79a261cd12b92879947bd340939a833a678632ce4f5c4a6feab4477e9c21cd43faac3b90b68b77dd0536c4149736 + languageName: node + linkType: hard + "tippy.js@npm:^6.3.1, tippy.js@npm:^6.3.7": version: 6.3.7 resolution: "tippy.js@npm:6.3.7" @@ -23793,6 +25090,15 @@ __metadata: languageName: node linkType: hard +"tr46@npm:^4.1.1": + version: 4.1.1 + resolution: "tr46@npm:4.1.1" + dependencies: + punycode: "npm:^2.3.0" + checksum: 10/ca811409c46de84618e4e7f90469184b50d16618b2f027a5ebeccb0d83ee7f51eca229e71f5b15cdec008ca247ad2ccabfdd3daf861604fcc7e341d0c35c30ca + languageName: node + linkType: hard + "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -24007,7 +25313,7 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:4.0.8": +"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.8": version: 4.0.8 resolution: "type-detect@npm:4.0.8" checksum: 10/5179e3b8ebc51fce1b13efb75fdea4595484433f9683bbc2dca6d99789dba4e602ab7922d2656f2ce8383987467f7770131d4a7f06a26287db0615d2f4c4ce7d @@ -24189,6 +25495,13 @@ __metadata: languageName: node linkType: hard +"ufo@npm:^1.5.3": + version: 1.5.3 + resolution: "ufo@npm:1.5.3" + checksum: 10/2b30dddd873c643efecdb58cfe457183cd4d95937ccdacca6942c697b87a2c578232c25a5149fda85436696bf0fdbc213bf2b220874712bc3e58c0fb00a2c950 + languageName: node + linkType: hard + "uglify-js@npm:^3.1.4": version: 3.17.4 resolution: "uglify-js@npm:3.17.4" @@ -24635,6 +25948,165 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:1.6.0": + version: 1.6.0 + resolution: "vite-node@npm:1.6.0" + dependencies: + cac: "npm:^6.7.14" + debug: "npm:^4.3.4" + pathe: "npm:^1.1.1" + picocolors: "npm:^1.0.0" + vite: "npm:^5.0.0" + bin: + vite-node: vite-node.mjs + checksum: 10/40230598c3c285cf65f407ac50b1c7753ab2dfa960de76ec1a95a0ce0ff963919d065c29ba538d9fb2fba3e0703a051d49d1ad6486001ba2f90616cc706ddc3d + languageName: node + linkType: hard + +"vite-plugin-static-copy@npm:^1.0.5": + version: 1.0.5 + resolution: "vite-plugin-static-copy@npm:1.0.5" + dependencies: + chokidar: "npm:^3.5.3" + fast-glob: "npm:^3.2.11" + fs-extra: "npm:^11.1.0" + picocolors: "npm:^1.0.0" + peerDependencies: + vite: ^5.0.0 + checksum: 10/8bc472f9a902bff443f24d8ff0e6ea58a74d31c1bb7f9eda4015cffe88bbe27d896d2c4af6b220908aef1b9b835b3bd0a8bde4b9707735cc2d4117f224ff24a7 + languageName: node + linkType: hard + +"vite@npm:^5.0.0": + version: 5.2.12 + resolution: "vite@npm:5.2.12" + dependencies: + esbuild: "npm:^0.20.1" + fsevents: "npm:~2.3.3" + postcss: "npm:^8.4.38" + rollup: "npm:^4.13.0" + peerDependencies: + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" + lightningcss: ^1.21.0 + sass: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + bin: + vite: bin/vite.js + checksum: 10/c27d3efff93016e8171b6a362f605ad5f78e24086292987097ad4a7382ae78d9e0659065976a13bf7b51ba0f593d675579010692097ef36d8a5cc965f3efec4c + languageName: node + linkType: hard + +"vite@npm:~5.0.0": + version: 5.0.13 + resolution: "vite@npm:5.0.13" + dependencies: + esbuild: "npm:^0.19.3" + fsevents: "npm:~2.3.3" + postcss: "npm:^8.4.32" + rollup: "npm:^4.2.0" + peerDependencies: + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" + lightningcss: ^1.21.0 + sass: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + bin: + vite: bin/vite.js + checksum: 10/e0da15142ecbe3e88dbb2682c86c7e468927ea35a04c6a57dae623c575d632f3150a1098905af2da5a598b604a5762bdf45f904d00a2ecc6e93042d904b01077 + languageName: node + linkType: hard + +"vitest@npm:^1.3.1": + version: 1.6.0 + resolution: "vitest@npm:1.6.0" + dependencies: + "@vitest/expect": "npm:1.6.0" + "@vitest/runner": "npm:1.6.0" + "@vitest/snapshot": "npm:1.6.0" + "@vitest/spy": "npm:1.6.0" + "@vitest/utils": "npm:1.6.0" + acorn-walk: "npm:^8.3.2" + chai: "npm:^4.3.10" + debug: "npm:^4.3.4" + execa: "npm:^8.0.1" + local-pkg: "npm:^0.5.0" + magic-string: "npm:^0.30.5" + pathe: "npm:^1.1.1" + picocolors: "npm:^1.0.0" + std-env: "npm:^3.5.0" + strip-literal: "npm:^2.0.0" + tinybench: "npm:^2.5.1" + tinypool: "npm:^0.8.3" + vite: "npm:^5.0.0" + vite-node: "npm:1.6.0" + why-is-node-running: "npm:^2.2.2" + peerDependencies: + "@edge-runtime/vm": "*" + "@types/node": ^18.0.0 || >=20.0.0 + "@vitest/browser": 1.6.0 + "@vitest/ui": 1.6.0 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 10/ad921a723ac9438636d37111f0b2ea5afd0ba4a7813fb75382b9f75574e10d533cf950573ebb9332a595ce197cb83593737a6b55a3b6e6eb00bddbcd0920a03e + languageName: node + linkType: hard + "void-elements@npm:3.1.0": version: 3.1.0 resolution: "void-elements@npm:3.1.0" @@ -24997,6 +26469,16 @@ __metadata: languageName: node linkType: hard +"whatwg-url@npm:^12.0.0, whatwg-url@npm:^12.0.1": + version: 12.0.1 + resolution: "whatwg-url@npm:12.0.1" + dependencies: + tr46: "npm:^4.1.1" + webidl-conversions: "npm:^7.0.0" + checksum: 10/3f60c803159aaa4af955533f38afc0a416905ae9d07e54a1682dd8bfcc45914ffa87e4faeab2c77dbd01e7942786bf3501bed39e2c81679af70ad9f89f300bcc + languageName: node + linkType: hard + "whatwg-url@npm:^5.0.0": version: 5.0.0 resolution: "whatwg-url@npm:5.0.0" @@ -25063,7 +26545,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.9": +"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.9": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" dependencies: @@ -25109,6 +26591,18 @@ __metadata: languageName: node linkType: hard +"why-is-node-running@npm:^2.2.2": + version: 2.2.2 + resolution: "why-is-node-running@npm:2.2.2" + dependencies: + siginfo: "npm:^2.0.0" + stackback: "npm:0.0.2" + bin: + why-is-node-running: cli.js + checksum: 10/f3582e0337f4b25537d492b1d40f00b978ce04b1d1eeea8f310bfa8aae8a7d11d118d672e2f0760c164ce3753a620a70aa29ff3620e340197624940cf9c08615 + languageName: node + linkType: hard + "wildcard@npm:^2.0.0": version: 2.0.1 resolution: "wildcard@npm:2.0.1" From 9f3176e3644169c032316abd79edd260ad9b15fe Mon Sep 17 00:00:00 2001 From: j8seangel Date: Tue, 4 Jun 2024 18:37:13 +0200 Subject: [PATCH 02/17] update yarn version --- apps/api-portal/cloudbuild.yaml | 2 +- apps/deck-playground/cloudbuild.yaml | 2 +- apps/fishing-map-e2e/cloudbuild.yaml | 2 +- apps/fishing-map/cloudbuild.yaml | 2 +- apps/image-labeler/.dockerignore | 1 - apps/image-labeler/cloudbuild.yaml | 10 ++-------- apps/real-time-prototype/cloudbuild.yaml | 2 +- apps/vessel-history/cloudbuild.yaml | 2 +- apps/vessel-history/cloudbuild_PR_tests.yaml | 2 +- cloudbuild.yaml | 2 +- libs/i18n-labels/cloudbuild.yaml | 2 +- 11 files changed, 11 insertions(+), 18 deletions(-) delete mode 100644 apps/image-labeler/.dockerignore diff --git a/apps/api-portal/cloudbuild.yaml b/apps/api-portal/cloudbuild.yaml index 68e2abd540..935cde01b1 100644 --- a/apps/api-portal/cloudbuild.yaml +++ b/apps/api-portal/cloudbuild.yaml @@ -18,7 +18,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/apps/deck-playground/cloudbuild.yaml b/apps/deck-playground/cloudbuild.yaml index 1fafdb8614..ab0b415642 100644 --- a/apps/deck-playground/cloudbuild.yaml +++ b/apps/deck-playground/cloudbuild.yaml @@ -18,7 +18,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/apps/fishing-map-e2e/cloudbuild.yaml b/apps/fishing-map-e2e/cloudbuild.yaml index 529c33943c..dddb43eb09 100644 --- a/apps/fishing-map-e2e/cloudbuild.yaml +++ b/apps/fishing-map-e2e/cloudbuild.yaml @@ -31,7 +31,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/apps/fishing-map/cloudbuild.yaml b/apps/fishing-map/cloudbuild.yaml index 2fbd3a154a..4620098376 100644 --- a/apps/fishing-map/cloudbuild.yaml +++ b/apps/fishing-map/cloudbuild.yaml @@ -18,7 +18,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/apps/image-labeler/.dockerignore b/apps/image-labeler/.dockerignore deleted file mode 100644 index 75db72a526..0000000000 --- a/apps/image-labeler/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -nginx.conf diff --git a/apps/image-labeler/cloudbuild.yaml b/apps/image-labeler/cloudbuild.yaml index bcff17381e..4bc5c488e3 100644 --- a/apps/image-labeler/cloudbuild.yaml +++ b/apps/image-labeler/cloudbuild.yaml @@ -51,17 +51,11 @@ steps: env: - 'NX_BRANCH=$_NX_BRANCH' - 'NX_CLOUD_AUTH_TOKEN=$_NX_CLOUD_AUTH_TOKEN' - - 'NEXT_PUBLIC_API_GATEWAY=$_NEXT_PUBLIC_API_GATEWAY' - - - id: 'docker-prepare' - waitFor: ['build-app'] - name: node:21 - entrypoint: yarn - args: ['nx', 'docker-prepare', 'image-labeler'] + - 'API_GATEWAY=$_API_GATEWAY' - name: 'gcr.io/kaniko-project/executor:latest' id: 'build-image' - waitFor: ['docker-prepare'] + waitFor: ['build-app'] args: [ '--destination=gcr.io/world-fishing-827/github.com/globalfishingwatch/image-labeler:$SHORT_SHA', diff --git a/apps/real-time-prototype/cloudbuild.yaml b/apps/real-time-prototype/cloudbuild.yaml index d2e7ff422d..2d768d3795 100644 --- a/apps/real-time-prototype/cloudbuild.yaml +++ b/apps/real-time-prototype/cloudbuild.yaml @@ -18,7 +18,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/apps/vessel-history/cloudbuild.yaml b/apps/vessel-history/cloudbuild.yaml index 5449273156..d9c4586336 100644 --- a/apps/vessel-history/cloudbuild.yaml +++ b/apps/vessel-history/cloudbuild.yaml @@ -18,7 +18,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/apps/vessel-history/cloudbuild_PR_tests.yaml b/apps/vessel-history/cloudbuild_PR_tests.yaml index d057c686ef..3c2add03f9 100644 --- a/apps/vessel-history/cloudbuild_PR_tests.yaml +++ b/apps/vessel-history/cloudbuild_PR_tests.yaml @@ -18,7 +18,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 852a53a96a..374ef451b2 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -21,7 +21,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable diff --git a/libs/i18n-labels/cloudbuild.yaml b/libs/i18n-labels/cloudbuild.yaml index 6c1c93d231..8f19cf1b40 100644 --- a/libs/i18n-labels/cloudbuild.yaml +++ b/libs/i18n-labels/cloudbuild.yaml @@ -18,7 +18,7 @@ steps: waitFor: ['restore_cache'] name: node:21 script: | - yarn set version 4.1.1 + yarn set version 4.2.2 yarn -v yarn install --immutable From 377513a0cc3eea74a0895e43f9b39a717982dd5f Mon Sep 17 00:00:00 2001 From: j8seangel Date: Wed, 5 Jun 2024 07:59:07 +0200 Subject: [PATCH 03/17] use tanstack router --- apps/image-labeler/index.html | 2 +- apps/image-labeler/src/app/app.tsx | 49 ---- .../src/features/projects/Projects.tsx | 37 +++ .../projects/projects.module.css} | 0 .../src/features/tasks/Tasks.tsx | 11 + .../src/features/tasks/tasks.module.css | 1 + apps/image-labeler/src/main.tsx | 37 ++- apps/image-labeler/src/routeTree.gen.ts | 82 +++++++ apps/image-labeler/src/routes/__root.tsx | 25 ++ apps/image-labeler/src/routes/index.lazy.tsx | 6 + .../src/routes/tasks.$taskId.lazy.tsx | 6 + apps/image-labeler/vite.config.mts | 5 + package.json | 4 +- yarn.lock | 213 ++++++++++++++---- 14 files changed, 369 insertions(+), 109 deletions(-) delete mode 100644 apps/image-labeler/src/app/app.tsx create mode 100644 apps/image-labeler/src/features/projects/Projects.tsx rename apps/image-labeler/src/{app/app.module.css => features/projects/projects.module.css} (100%) create mode 100644 apps/image-labeler/src/features/tasks/Tasks.tsx create mode 100644 apps/image-labeler/src/features/tasks/tasks.module.css create mode 100644 apps/image-labeler/src/routeTree.gen.ts create mode 100644 apps/image-labeler/src/routes/__root.tsx create mode 100644 apps/image-labeler/src/routes/index.lazy.tsx create mode 100644 apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx diff --git a/apps/image-labeler/index.html b/apps/image-labeler/index.html index c98a53db73..b049fd17c6 100644 --- a/apps/image-labeler/index.html +++ b/apps/image-labeler/index.html @@ -10,7 +10,7 @@ -
+
diff --git a/apps/image-labeler/src/app/app.tsx b/apps/image-labeler/src/app/app.tsx deleted file mode 100644 index f6273812d3..0000000000 --- a/apps/image-labeler/src/app/app.tsx +++ /dev/null @@ -1,49 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { Route, Routes, Link } from 'react-router-dom' -import { GFWAPI } from '@globalfishingwatch/api-client' -import { useGFWLogin, useGFWLoginRedirect } from '@globalfishingwatch/react-hooks/use-login' -import { Spinner } from '@globalfishingwatch/ui-components/spinner' -import styles from './app.module.css' - -export function App() { - const login = useGFWLogin() - useGFWLoginRedirect(login) - if (!login.logged) { - return - } - return ( -
-
-
    -
  • - Home -
  • -
  • - Page 2 -
  • -
-
- - - This is the generated root route. Click here for page 2. -
- } - /> - - Click here to go back to root page. - - } - /> - - {/* END: routes */} - - ) -} - -export default App diff --git a/apps/image-labeler/src/features/projects/Projects.tsx b/apps/image-labeler/src/features/projects/Projects.tsx new file mode 100644 index 0000000000..35010f659e --- /dev/null +++ b/apps/image-labeler/src/features/projects/Projects.tsx @@ -0,0 +1,37 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Link } from '@tanstack/react-router' +import { useGFWLogin, useGFWLoginRedirect } from '@globalfishingwatch/react-hooks/use-login' +import { Spinner } from '@globalfishingwatch/ui-components/spinner' +import styles from './projects.module.css' + +const tasks = [ + { id: 1, name: 'Task 1' }, + { id: 2, name: 'Task 2' }, +] + +export function App() { + const login = useGFWLogin() + useGFWLoginRedirect(login) + if (!login.logged) { + return + } + return ( +
+

Projects page

+ {tasks.map((task) => ( +
+ + {task.name} + +
+ ))} +
+ ) +} + +export default App diff --git a/apps/image-labeler/src/app/app.module.css b/apps/image-labeler/src/features/projects/projects.module.css similarity index 100% rename from apps/image-labeler/src/app/app.module.css rename to apps/image-labeler/src/features/projects/projects.module.css diff --git a/apps/image-labeler/src/features/tasks/Tasks.tsx b/apps/image-labeler/src/features/tasks/Tasks.tsx new file mode 100644 index 0000000000..bc0ebf2a4b --- /dev/null +++ b/apps/image-labeler/src/features/tasks/Tasks.tsx @@ -0,0 +1,11 @@ +import { getRouteApi } from '@tanstack/react-router' +import styles from './tasks.module.css' + +const route = getRouteApi('/tasks/$taskId') + +export function App() { + const { taskId } = route.useParams() + return

Your tasks: {taskId}

+} + +export default App diff --git a/apps/image-labeler/src/features/tasks/tasks.module.css b/apps/image-labeler/src/features/tasks/tasks.module.css new file mode 100644 index 0000000000..7b88fbabf8 --- /dev/null +++ b/apps/image-labeler/src/features/tasks/tasks.module.css @@ -0,0 +1 @@ +/* Your styles goes here. */ diff --git a/apps/image-labeler/src/main.tsx b/apps/image-labeler/src/main.tsx index e5880901e9..addd688f3b 100644 --- a/apps/image-labeler/src/main.tsx +++ b/apps/image-labeler/src/main.tsx @@ -1,13 +1,26 @@ -import { StrictMode } from 'react' -import * as ReactDOM from 'react-dom/client' -import { BrowserRouter } from 'react-router-dom' -import App from './app/app' +import React, { StrictMode } from 'react' +import ReactDOM from 'react-dom/client' +import { RouterProvider, createRouter } from '@tanstack/react-router' +// Import the generated route tree +import { routeTree } from './routeTree.gen' -const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement) -root.render( - - - - - -) +// Create a new router instance +export const router = createRouter({ routeTree }) + +// Register the router instance for type safety +declare module '@tanstack/react-router' { + interface Register { + router: typeof router + } +} + +// Render the app +const rootElement = document.getElementById('app')! +if (!rootElement?.innerHTML) { + const root = ReactDOM.createRoot(rootElement) + root.render( + + + + ) +} diff --git a/apps/image-labeler/src/routeTree.gen.ts b/apps/image-labeler/src/routeTree.gen.ts new file mode 100644 index 0000000000..f4758b231d --- /dev/null +++ b/apps/image-labeler/src/routeTree.gen.ts @@ -0,0 +1,82 @@ +/* prettier-ignore-start */ + +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file is auto-generated by TanStack Router + +import { createFileRoute } from '@tanstack/react-router' + +// Import Routes + +import { Route as rootRoute } from './routes/__root' + +// Create Virtual Routes + +const IndexLazyImport = createFileRoute('/')() +const TasksTaskIdLazyImport = createFileRoute('/tasks/$taskId')() + +// Create/Update Routes + +const IndexLazyRoute = IndexLazyImport.update({ + path: '/', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route)) + +const TasksTaskIdLazyRoute = TasksTaskIdLazyImport.update({ + path: '/tasks/$taskId', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/tasks.$taskId.lazy').then((d) => d.Route)) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexLazyImport + parentRoute: typeof rootRoute + } + '/tasks/$taskId': { + id: '/tasks/$taskId' + path: '/tasks/$taskId' + fullPath: '/tasks/$taskId' + preLoaderRoute: typeof TasksTaskIdLazyImport + parentRoute: typeof rootRoute + } + } +} + +// Create and export the route tree + +export const routeTree = rootRoute.addChildren({ + IndexLazyRoute, + TasksTaskIdLazyRoute, +}) + +/* prettier-ignore-end */ + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/", + "/tasks/$taskId" + ] + }, + "/": { + "filePath": "index.lazy.tsx" + }, + "/tasks/$taskId": { + "filePath": "tasks.$taskId.lazy.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/apps/image-labeler/src/routes/__root.tsx b/apps/image-labeler/src/routes/__root.tsx new file mode 100644 index 0000000000..ba05c66359 --- /dev/null +++ b/apps/image-labeler/src/routes/__root.tsx @@ -0,0 +1,25 @@ +import { createRootRoute, Outlet } from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/router-devtools' +import { Fragment } from 'react' +import { Spinner } from '@globalfishingwatch/ui-components/spinner' +import { useGFWLogin, useGFWLoginRedirect } from '@globalfishingwatch/react-hooks/use-login' + +const RootComponent = () => { + const login = useGFWLogin() + useGFWLoginRedirect(login) + + if (!login.logged) { + return + } + + return ( + + + + + ) +} + +export const Route = createRootRoute({ + component: RootComponent, +}) diff --git a/apps/image-labeler/src/routes/index.lazy.tsx b/apps/image-labeler/src/routes/index.lazy.tsx new file mode 100644 index 0000000000..ca78de6202 --- /dev/null +++ b/apps/image-labeler/src/routes/index.lazy.tsx @@ -0,0 +1,6 @@ +import { createLazyFileRoute } from '@tanstack/react-router' +import Projects from '../features/projects/projects' + +export const Route = createLazyFileRoute('/')({ + component: Projects, +}) diff --git a/apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx b/apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx new file mode 100644 index 0000000000..e6152ece7c --- /dev/null +++ b/apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx @@ -0,0 +1,6 @@ +import { createLazyFileRoute } from '@tanstack/react-router' +import TasksComponent from '../features/tasks/tasks' + +export const Route = createLazyFileRoute('/tasks/$taskId')({ + component: TasksComponent, +}) diff --git a/apps/image-labeler/vite.config.mts b/apps/image-labeler/vite.config.mts index 70c10c4d6c..fde5df82e4 100644 --- a/apps/image-labeler/vite.config.mts +++ b/apps/image-labeler/vite.config.mts @@ -3,6 +3,7 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { viteStaticCopy } from 'vite-plugin-static-copy' import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' +import { TanStackRouterVite } from '@tanstack/router-vite-plugin' export default defineConfig({ root: __dirname, @@ -21,6 +22,10 @@ export default defineConfig({ plugins: [ react(), nxViteTsPaths(), + TanStackRouterVite({ + routesDirectory: './apps/image-labeler/src/routes', + generatedRouteTree: './apps/image-labeler/src/routeTree.gen.ts', + }), viteStaticCopy({ targets: [ { diff --git a/package.json b/package.json index d64a49a84a..d5df1e2c0f 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@reduxjs/toolkit": "^2.2.1", "@researchgate/react-intersection-observer": "1.3.5", "@tanstack/react-query": "^4.36.1", + "@tanstack/react-router": "^1.34.9", "@tippyjs/react": "^4.2.6", "@tmcw/togeojson": "^5.8.1", "@turf/bbox": "6.5.0", @@ -116,7 +117,6 @@ "react-query": "^3.39.3", "react-range": "^1.8.14", "react-redux": "^9.1.0", - "react-router-dom": "6.11.2", "react-spring": "^9.7.3", "react-sticky-el": "2.1.0", "react-virtualized-auto-sizer": "^1.0.20", @@ -161,6 +161,8 @@ "@swc/cli": "~0.1.62", "@swc/core": "~1.3.85", "@swc/helpers": "~0.5.2", + "@tanstack/router-devtools": "^1.34.9", + "@tanstack/router-vite-plugin": "^1.34.8", "@testing-library/react": "14.0.0", "@types/circular-dependency-plugin": "^5.0.8", "@types/d3": "^7.4.3", diff --git a/yarn.lock b/yarn.lock index 528ebc0e93..8e4137e543 100644 --- a/yarn.lock +++ b/yarn.lock @@ -109,7 +109,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.24.5": +"@babel/core@npm:^7.23.7, @babel/core@npm:^7.24.5": version: 7.24.6 resolution: "@babel/core@npm:7.24.6" dependencies: @@ -146,27 +146,27 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.24.4, @babel/generator@npm:^7.7.2": - version: 7.24.4 - resolution: "@babel/generator@npm:7.24.4" +"@babel/generator@npm:^7.23.6, @babel/generator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/generator@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.24.0" + "@babel/types": "npm:^7.24.6" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^2.5.1" - checksum: 10/69e1772dcf8f95baec951f422cca091d59a3f29b5eedc989ad87f7262289b94625983f6fe654302ca17aae0a32f9232332b83fcc85533311d6267b09c58b1061 + checksum: 10/247002f1246c3cb825497dc7ce55dc1d10c5f0486f546d1c087aeed7e38df6eb7837758fdfa2ae1234c26c60f883756fd79b7b3f0443771bd79bdfbb0dde8cd4 languageName: node linkType: hard -"@babel/generator@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/generator@npm:7.24.6" +"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.24.4, @babel/generator@npm:^7.7.2": + version: 7.24.4 + resolution: "@babel/generator@npm:7.24.4" dependencies: - "@babel/types": "npm:^7.24.6" + "@babel/types": "npm:^7.24.0" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^2.5.1" - checksum: 10/247002f1246c3cb825497dc7ce55dc1d10c5f0486f546d1c087aeed7e38df6eb7837758fdfa2ae1234c26c60f883756fd79b7b3f0443771bd79bdfbb0dde8cd4 + checksum: 10/69e1772dcf8f95baec951f422cca091d59a3f29b5eedc989ad87f7262289b94625983f6fe654302ca17aae0a32f9232332b83fcc85533311d6267b09c58b1061 languageName: node linkType: hard @@ -1833,6 +1833,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.21.0": + version: 7.24.6 + resolution: "@babel/runtime@npm:7.24.6" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: 10/6c4e12731cd9206a883c19d48fa04f6aaaf7ee83f049b22631e6521b866edc20832b4d5db30aa86d8ae799c4dcf57761fe8a4af2bf7e233245c079c1dafb5668 + languageName: node + linkType: hard + "@babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0, @babel/template@npm:^7.3.3": version: 7.24.0 resolution: "@babel/template@npm:7.24.0" @@ -2876,6 +2885,9 @@ __metadata: "@swc/core": "npm:~1.3.85" "@swc/helpers": "npm:~0.5.2" "@tanstack/react-query": "npm:^4.36.1" + "@tanstack/react-router": "npm:^1.34.9" + "@tanstack/router-devtools": "npm:^1.34.9" + "@tanstack/router-vite-plugin": "npm:^1.34.8" "@testing-library/react": "npm:14.0.0" "@tippyjs/react": "npm:^4.2.6" "@tmcw/togeojson": "npm:^5.8.1" @@ -3011,7 +3023,6 @@ __metadata: react-query: "npm:^3.39.3" react-range: "npm:^1.8.14" react-redux: "npm:^9.1.0" - react-router-dom: "npm:6.11.2" react-spring: "npm:^9.7.3" react-sticky-el: "npm:2.1.0" react-virtualized-auto-sizer: "npm:^1.0.20" @@ -5361,13 +5372,6 @@ __metadata: languageName: node linkType: hard -"@remix-run/router@npm:1.6.2": - version: 1.6.2 - resolution: "@remix-run/router@npm:1.6.2" - checksum: 10/c261c3b52f08d7fcacce9c66d68dba3b6f0c8263ea15f69f9f1c89734685cdfe4f383c879324acade68cb331d48e3deca9ec00734abe08d9694e529096907f40 - languageName: node - linkType: hard - "@researchgate/react-intersection-observer@npm:1.3.5": version: 1.3.5 resolution: "@researchgate/react-intersection-observer@npm:1.3.5" @@ -6113,6 +6117,13 @@ __metadata: languageName: node linkType: hard +"@tanstack/history@npm:1.31.16": + version: 1.31.16 + resolution: "@tanstack/history@npm:1.31.16" + checksum: 10/5fc803aa806bd25bc67d88cdf52583911bdac5d508bba2d9738e6e60e3500f9f523f2f6efc65532eda22fc694aa285e8a20f22bb76836e8cf815f32826f7938e + languageName: node + linkType: hard + "@tanstack/match-sorter-utils@npm:8.11.8": version: 8.11.8 resolution: "@tanstack/match-sorter-utils@npm:8.11.8" @@ -6148,6 +6159,34 @@ __metadata: languageName: node linkType: hard +"@tanstack/react-router@npm:^1.34.9": + version: 1.34.9 + resolution: "@tanstack/react-router@npm:1.34.9" + dependencies: + "@tanstack/history": "npm:1.31.16" + "@tanstack/react-store": "npm:^0.2.1" + tiny-invariant: "npm:^1.3.1" + tiny-warning: "npm:^1.0.3" + peerDependencies: + react: ">=16.8" + react-dom: ">=16.8" + checksum: 10/d37653a9d0d25c1c3eccb307f13e7dbc480ff89290026386c97be1578d4e9c2fac64c4b5ece2544daa80b9c93e1b5e7c2829ba93567ee660b7182be528683d02 + languageName: node + linkType: hard + +"@tanstack/react-store@npm:^0.2.1": + version: 0.2.1 + resolution: "@tanstack/react-store@npm:0.2.1" + dependencies: + "@tanstack/store": "npm:0.1.3" + use-sync-external-store: "npm:^1.2.0" + peerDependencies: + react: ">=16" + react-dom: ">=16" + checksum: 10/bda3c394e0a2eac08d5c0545a18826ac52fd6d1dd6d142e27bf3a0005aa289015d9b28c25015c1954af410481b50b1a8e811144354fb3bae3b87b547ad32cc25 + languageName: node + linkType: hard + "@tanstack/react-table@npm:8.13.2": version: 8.13.2 resolution: "@tanstack/react-table@npm:8.13.2" @@ -6172,6 +6211,62 @@ __metadata: languageName: node linkType: hard +"@tanstack/router-devtools@npm:^1.34.9": + version: 1.34.9 + resolution: "@tanstack/router-devtools@npm:1.34.9" + dependencies: + clsx: "npm:^2.1.0" + date-fns: "npm:^2.29.1" + goober: "npm:^2.1.14" + peerDependencies: + "@tanstack/react-router": ^1.34.9 + react: ">=16.8" + react-dom: ">=16.8" + checksum: 10/468c81ce24f8ff4bc367cef2b3bc16284579bd6e9ffd110692ad8161e105d8fee4a708e34c96744cd4ccd31101a193f7ca55b36b31b079a48d06a1b718df80c2 + languageName: node + linkType: hard + +"@tanstack/router-generator@npm:1.34.8": + version: 1.34.8 + resolution: "@tanstack/router-generator@npm:1.34.8" + dependencies: + prettier: "npm:^3.1.1" + zod: "npm:^3.22.4" + checksum: 10/dbcb83ee34edee7b6473385e2eaf5992eee555d6209d083787bff8190d03bf14f55e85fc3f70c4c9883275250ee0264f0d01b407fae11eb0462d0320f39ee596 + languageName: node + linkType: hard + +"@tanstack/router-vite-plugin@npm:^1.34.8": + version: 1.34.8 + resolution: "@tanstack/router-vite-plugin@npm:1.34.8" + dependencies: + "@babel/core": "npm:^7.23.7" + "@babel/generator": "npm:^7.23.6" + "@babel/plugin-syntax-jsx": "npm:^7.24.1" + "@babel/plugin-syntax-typescript": "npm:^7.24.1" + "@babel/plugin-transform-react-jsx": "npm:^7.23.4" + "@babel/plugin-transform-typescript": "npm:^7.24.1" + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + "@tanstack/router-generator": "npm:1.34.8" + "@types/babel__core": "npm:^7.20.5" + "@types/babel__generator": "npm:^7.6.8" + "@types/babel__template": "npm:^7.4.4" + "@types/babel__traverse": "npm:^7.20.5" + "@vitejs/plugin-react": "npm:^4.2.1" + zod: "npm:^3.22.4" + checksum: 10/1a6268a47e17dca2488e061e55e31f095186db02b6576fe959a377381c4e3a576bd9948e342d18ec9c68975962969acccf1579e51bc7e95da0b23e8090c7b806 + languageName: node + linkType: hard + +"@tanstack/store@npm:0.1.3": + version: 0.1.3 + resolution: "@tanstack/store@npm:0.1.3" + checksum: 10/90a528e004553538be099b61d357e9dd1af7c0fb35f37b3c50a8a17462c5cd8c8d269d912f60c6dfcc18387a961f8c5a48e0b1e848db7f9d6ad357e45529294b + languageName: node + linkType: hard + "@tanstack/table-core@npm:8.13.2": version: 8.13.2 resolution: "@tanstack/table-core@npm:8.13.2" @@ -7714,7 +7809,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__generator@npm:*": +"@types/babel__generator@npm:*, @types/babel__generator@npm:^7.6.8": version: 7.6.8 resolution: "@types/babel__generator@npm:7.6.8" dependencies: @@ -7723,7 +7818,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__template@npm:*": +"@types/babel__template@npm:*, @types/babel__template@npm:^7.4.4": version: 7.4.4 resolution: "@types/babel__template@npm:7.4.4" dependencies: @@ -7742,6 +7837,15 @@ __metadata: languageName: node linkType: hard +"@types/babel__traverse@npm:^7.20.5": + version: 7.20.6 + resolution: "@types/babel__traverse@npm:7.20.6" + dependencies: + "@babel/types": "npm:^7.20.7" + checksum: 10/63d13a3789aa1e783b87a8b03d9fb2c2c90078de7782422feff1631b8c2a25db626e63a63ac5a1465d47359201c73069dacb4b52149d17c568187625da3064ae + languageName: node + linkType: hard + "@types/body-parser@npm:*": version: 1.19.5 resolution: "@types/body-parser@npm:1.19.5" @@ -9102,7 +9206,7 @@ __metadata: languageName: node linkType: hard -"@vitejs/plugin-react@npm:^4.2.0": +"@vitejs/plugin-react@npm:^4.2.0, @vitejs/plugin-react@npm:^4.2.1": version: 4.3.0 resolution: "@vitejs/plugin-react@npm:4.3.0" dependencies: @@ -12743,6 +12847,15 @@ __metadata: languageName: node linkType: hard +"date-fns@npm:^2.29.1": + version: 2.30.0 + resolution: "date-fns@npm:2.30.0" + dependencies: + "@babel/runtime": "npm:^7.21.0" + checksum: 10/70b3e8ea7aaaaeaa2cd80bd889622a4bcb5d8028b4de9162cbcda359db06e16ff6e9309e54eead5341e71031818497f19aaf9839c87d1aba1e27bb4796e758a9 + languageName: node + linkType: hard + "dateformat@npm:^4.5.1": version: 4.6.3 resolution: "dateformat@npm:4.6.3" @@ -15764,6 +15877,15 @@ __metadata: languageName: node linkType: hard +"goober@npm:^2.1.14": + version: 2.1.14 + resolution: "goober@npm:2.1.14" + peerDependencies: + csstype: ^3.0.10 + checksum: 10/372f18333ef64c403d29be7c1175cc9cd74cb947ec52cd42fbb1cf3f9870ac1dfec9c7671192cbf47ebc0ec17d8b05b6ef9a2b92952397d5b555a692381d5eaa + languageName: node + linkType: hard + "google-auth-library@npm:9.4.1": version: 9.4.1 resolution: "google-auth-library@npm:9.4.1" @@ -21587,6 +21709,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.1.1": + version: 3.3.0 + resolution: "prettier@npm:3.3.0" + bin: + prettier: bin/prettier.cjs + checksum: 10/e55233f8e4b5f96f52180dbfa424ae797a98a9b8a9a7a79de5004e522c02b423e71927ed99d855dbfcd00dc3b82e5f6fb304cfe117cc4e7c8477d883df2d8984 + languageName: node + linkType: hard + "pretty-bytes@npm:^5.3.0, pretty-bytes@npm:^5.4.1, pretty-bytes@npm:^5.6.0": version: 5.6.0 resolution: "pretty-bytes@npm:5.6.0" @@ -22102,30 +22233,6 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:6.11.2": - version: 6.11.2 - resolution: "react-router-dom@npm:6.11.2" - dependencies: - "@remix-run/router": "npm:1.6.2" - react-router: "npm:6.11.2" - peerDependencies: - react: ">=16.8" - react-dom: ">=16.8" - checksum: 10/85575793cbdb84b05e9c33fef6f81e6b09e9f2606d2ba03392f83689dbb240212e5b22634b95049fc19364e9b44d45a519387d1bff4eba8a163548aa3376bc0f - languageName: node - linkType: hard - -"react-router@npm:6.11.2": - version: 6.11.2 - resolution: "react-router@npm:6.11.2" - dependencies: - "@remix-run/router": "npm:1.6.2" - peerDependencies: - react: ">=16.8" - checksum: 10/a40d1ea78e3b5b3167ed6cbaf74b2e60592fd1822b9f94a2499933bf699130a81f669bc06bdf34f38489a96d31510848c21254a48e49038b18ecbf42993eaa34 - languageName: node - linkType: hard - "react-smooth@npm:^2.0.5": version: 2.0.5 resolution: "react-smooth@npm:2.0.5" @@ -24920,6 +25027,13 @@ __metadata: languageName: node linkType: hard +"tiny-warning@npm:^1.0.3": + version: 1.0.3 + resolution: "tiny-warning@npm:1.0.3" + checksum: 10/da62c4acac565902f0624b123eed6dd3509bc9a8d30c06e017104bedcf5d35810da8ff72864400ad19c5c7806fc0a8323c68baf3e326af7cb7d969f846100d71 + languageName: node + linkType: hard + "tinybench@npm:^2.5.1": version: 2.8.0 resolution: "tinybench@npm:2.8.0" @@ -27081,3 +27195,10 @@ __metadata: checksum: 10/2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801 languageName: node linkType: hard + +"zod@npm:^3.22.4": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 10/846fd73e1af0def79c19d510ea9e4a795544a67d5b34b7e1c4d0425bf6bfd1c719446d94cdfa1721c1987d891321d61f779e8236fde517dc0e524aa851a6eff1 + languageName: node + linkType: hard From b75754fda1c2cc845529a32b738f1c05d9c235fb Mon Sep 17 00:00:00 2001 From: satellitestudiodesign Date: Wed, 5 Jun 2024 13:29:43 +0200 Subject: [PATCH 04/17] UI --- apps/image-labeler/src/api/base.ts | 28 +++++ apps/image-labeler/src/api/project.ts | 27 +++++ apps/image-labeler/src/api/projects-list.ts | 22 ++++ apps/image-labeler/src/api/task.ts | 30 +++++ .../src/features/project/Project.module.css | 4 + .../src/features/project/Project.tsx | 51 +++++++++ .../src/features/project/Task.module.css | 50 ++++++++ .../src/features/project/Task.tsx | 108 ++++++++++++++++++ .../projects-list/ProjectsList.module.css | 29 +++++ .../features/projects-list/ProjectsList.tsx | 53 +++++++++ .../src/features/projects/Projects.tsx | 37 ------ .../src/features/projects/projects.module.css | 1 - .../src/features/tasks/Tasks.tsx | 11 -- .../src/features/tasks/tasks.module.css | 1 - apps/image-labeler/src/main.module.css | 6 + apps/image-labeler/src/main.tsx | 26 ++++- apps/image-labeler/src/routeTree.gen.ts | 28 ++--- apps/image-labeler/src/routes/index.lazy.tsx | 2 +- .../src/routes/project.$projectId.lazy.tsx | 6 + .../src/routes/tasks.$taskId.lazy.tsx | 6 - apps/image-labeler/vite.config.mts | 2 + libs/ui-components/src/choice/Choice.tsx | 6 +- package.json | 1 + yarn.lock | 20 +++- 24 files changed, 478 insertions(+), 77 deletions(-) create mode 100644 apps/image-labeler/src/api/base.ts create mode 100644 apps/image-labeler/src/api/project.ts create mode 100644 apps/image-labeler/src/api/projects-list.ts create mode 100644 apps/image-labeler/src/api/task.ts create mode 100644 apps/image-labeler/src/features/project/Project.module.css create mode 100644 apps/image-labeler/src/features/project/Project.tsx create mode 100644 apps/image-labeler/src/features/project/Task.module.css create mode 100644 apps/image-labeler/src/features/project/Task.tsx create mode 100644 apps/image-labeler/src/features/projects-list/ProjectsList.module.css create mode 100644 apps/image-labeler/src/features/projects-list/ProjectsList.tsx delete mode 100644 apps/image-labeler/src/features/projects/Projects.tsx delete mode 100644 apps/image-labeler/src/features/projects/projects.module.css delete mode 100644 apps/image-labeler/src/features/tasks/Tasks.tsx delete mode 100644 apps/image-labeler/src/features/tasks/tasks.module.css create mode 100644 apps/image-labeler/src/main.module.css create mode 100644 apps/image-labeler/src/routes/project.$projectId.lazy.tsx delete mode 100644 apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx diff --git a/apps/image-labeler/src/api/base.ts b/apps/image-labeler/src/api/base.ts new file mode 100644 index 0000000000..487e654fea --- /dev/null +++ b/apps/image-labeler/src/api/base.ts @@ -0,0 +1,28 @@ +import { BaseQueryFn } from '@reduxjs/toolkit/query/react' +import { GFWAPI, ParsedAPIError, parseAPIError } from '@globalfishingwatch/api-client' + +export const gfwBaseQuery = + ( + { baseUrl, method }: { baseUrl: string; method?: 'GET' | 'POST' } = { + baseUrl: '', + method: 'GET', + } + ): BaseQueryFn< + { + url: string + signal?: AbortSignal + body?: any + }, + Response, + ParsedAPIError + > => + async ({ url, signal, body }) => { + try { + const data = await GFWAPI.fetch(baseUrl + url, { signal, method, body }) + return { data } + } catch (gfwApiError: any) { + return { + error: parseAPIError(gfwApiError), + } + } + } diff --git a/apps/image-labeler/src/api/project.ts b/apps/image-labeler/src/api/project.ts new file mode 100644 index 0000000000..d7bc779f49 --- /dev/null +++ b/apps/image-labeler/src/api/project.ts @@ -0,0 +1,27 @@ +import { createApi } from '@reduxjs/toolkit/query/react' +import { gfwBaseQuery } from './base' + +type LabellingProjectsApiParams = { + projectId: string + limit: number +} + +export const projectApi = createApi({ + reducerPath: 'projectApi', + baseQuery: gfwBaseQuery({ + baseUrl: '/labelling-projects', + }), + endpoints: (builder) => ({ + getLabellingProjectTasks: builder.query({ + query: ({ projectId, limit }: LabellingProjectsApiParams) => { + return { + url: `/${projectId}/task?limit=${limit}`, + } + }, + }), + }), +}) + +// Export hooks for usage in functional components, which are +// auto-generated based on the defined endpoints +export const { useGetLabellingProjectTasksQuery } = projectApi diff --git a/apps/image-labeler/src/api/projects-list.ts b/apps/image-labeler/src/api/projects-list.ts new file mode 100644 index 0000000000..7846a8c92f --- /dev/null +++ b/apps/image-labeler/src/api/projects-list.ts @@ -0,0 +1,22 @@ +import { createApi } from '@reduxjs/toolkit/query/react' +import { gfwBaseQuery } from './base' + +export const projectsListApi = createApi({ + reducerPath: 'projectsListApi', + baseQuery: gfwBaseQuery({ + baseUrl: '/labelling-projects', + }), + endpoints: (builder) => ({ + getLabellingProjectsList: builder.query({ + query: () => { + return { + url: '', + } + }, + }), + }), +}) + +// Export hooks for usage in functional components, which are +// auto-generated based on the defined endpoints +export const { useGetLabellingProjectsListQuery } = projectsListApi diff --git a/apps/image-labeler/src/api/task.ts b/apps/image-labeler/src/api/task.ts new file mode 100644 index 0000000000..dc6e47eb26 --- /dev/null +++ b/apps/image-labeler/src/api/task.ts @@ -0,0 +1,30 @@ +import { createApi } from '@reduxjs/toolkit/query/react' +import { gfwBaseQuery } from './base' + +export type TaskParams = { + projectId: string + taskId: string + label: string +} + +// Define a service using a base URL and expected endpoints +export const taskApi = createApi({ + reducerPath: 'taskApi', + baseQuery: gfwBaseQuery({ + baseUrl: `/labelling-projects`, + method: 'POST', + }), + endpoints: (builder) => ({ + setTask: builder.mutation({ + query: (body) => ({ + url: `/${body.projectId}/task`, + method: 'POST', + body: { id: body.taskId, label: body.label }, + }), + }), + }), +}) + +// Export hooks for usage in functional components, which are +// auto-generated based on the defined endpoints +export const { useSetTaskMutation } = taskApi diff --git a/apps/image-labeler/src/features/project/Project.module.css b/apps/image-labeler/src/features/project/Project.module.css new file mode 100644 index 0000000000..05484fdc67 --- /dev/null +++ b/apps/image-labeler/src/features/project/Project.module.css @@ -0,0 +1,4 @@ +.pageTitle { + font: var(--font-XL); + margin-bottom: var(--space-M); +} diff --git a/apps/image-labeler/src/features/project/Project.tsx b/apps/image-labeler/src/features/project/Project.tsx new file mode 100644 index 0000000000..424623d1e3 --- /dev/null +++ b/apps/image-labeler/src/features/project/Project.tsx @@ -0,0 +1,51 @@ +import { getRouteApi } from '@tanstack/react-router' +import { useEffect, useMemo, useState } from 'react' +import { set } from 'lodash' +import { Spinner } from '@globalfishingwatch/ui-components/spinner' +import { useGetLabellingProjectTasksQuery } from '../../api/project' +import styles from './Project.module.css' +import Task, { LabellingTask } from './Task' + +const route = getRouteApi('/project/$projectId') + +export function Project() { + const { projectId } = route.useParams() + + const { data, isLoading } = useGetLabellingProjectTasksQuery({ projectId, limit: 25 }) + + const [activeTaskId, setActiveTaskId] = useState() + + useEffect(() => { + if (!activeTaskId) { + setActiveTaskId(data?.entries[0]?.id) + } + }, [activeTaskId, data]) + + if (isLoading || !data) { + return + } + + const setNextTask = () => { + const currentIndex = (data?.entries as LabellingTask[]).findIndex( + (task) => task.id === activeTaskId + ) + setActiveTaskId((data?.entries as LabellingTask[])[currentIndex + 1]?.id) + } + + return ( +
+

Project: {projectId}

+ {(data?.entries as LabellingTask[]).map((task, index) => ( + + ))} +
+ ) +} + +export default Project diff --git a/apps/image-labeler/src/features/project/Task.module.css b/apps/image-labeler/src/features/project/Task.module.css new file mode 100644 index 0000000000..520e419dd4 --- /dev/null +++ b/apps/image-labeler/src/features/project/Task.module.css @@ -0,0 +1,50 @@ +.task { + border: var(--border); + border-bottom: none; + padding: var(--space-S); + display: flex; + align-items: center; + justify-content: space-between; +} + +.task:last-child { + border-bottom: var(--border); +} + +.open { + padding: var(--space-L); + flex-direction: column; + align-items: center; + gap: var(--space-S); +} + +.images { + display: flex; + gap: var(--space-S); +} + +.images img { + width: 5rem; + background-color: var(--color-terthiary-blue); +} + +.open .images { + width: 100%; + max-width: 80vh; +} + +.open .images img { + width: 100%; +} + +.labels { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--space-S); +} + +.buttons { + display: flex; + gap: var(--space-S); +} diff --git a/apps/image-labeler/src/features/project/Task.tsx b/apps/image-labeler/src/features/project/Task.tsx new file mode 100644 index 0000000000..3e9c58d03b --- /dev/null +++ b/apps/image-labeler/src/features/project/Task.tsx @@ -0,0 +1,108 @@ +import cx from 'classnames' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { Button } from '@globalfishingwatch/ui-components/button' +import { Choice, ChoiceOption } from '@globalfishingwatch/ui-components/choice' +import { Spinner } from '@globalfishingwatch/ui-components/spinner' +import { useSetTaskMutation } from '../../api/task' +import styles from './Task.module.css' + +export type LabellingTask = { + id: string + labels: string[] + metadata: { + score: number + } + thumbnails: string[] +} + +type TaskProps = { + projectId: string + task: LabellingTask + open: boolean + onFinishTask: () => void +} + +export function Task({ projectId, task, open, onFinishTask }: TaskProps) { + const options: ChoiceOption[] = useMemo( + () => + task.labels.map((label, index) => ({ + id: label, + label: `${label} (${index + 1})`, + })), + [task.labels] + ) + const [activeOption, setActiveOption] = useState() + const [setTask, { isLoading, data, error }] = useSetTaskMutation({ + fixedCacheKey: [projectId, task.id].join(), + }) + + const handleSubmit = useCallback(() => { + if (activeOption) { + console.log('activeOption:', activeOption) + onFinishTask() + setTask({ projectId, taskId: task.id, label: activeOption }) + } + }, [activeOption, onFinishTask, projectId, setTask, task.id]) + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + e.preventDefault() + if (e.key === 'Enter') { + handleSubmit() + return + } + if (e.key === 'Escape') { + onFinishTask() + return + } + const option = options[parseInt(e.key) - 1] + if (option) { + setOption(option) + } + } + if (open) { + window.addEventListener('keydown', handleKeyDown) + } + return () => { + window.removeEventListener('keydown', handleKeyDown) + } + }, [handleSubmit, open, options]) + + const setOption = (option: ChoiceOption) => { + setActiveOption(option.id) + } + + return ( +
+
+ {task.thumbnails.map((thumbnail, index) => ( + thumbnail + ))} +
+ {open ? ( +
+ +
+ + +
+
+ ) : ( +
+ {isLoading ? : } + {error !== undefined &&

{JSON.stringify(error)}

} +
+ )} +
+ ) +} + +export default Task diff --git a/apps/image-labeler/src/features/projects-list/ProjectsList.module.css b/apps/image-labeler/src/features/projects-list/ProjectsList.module.css new file mode 100644 index 0000000000..b8971d0340 --- /dev/null +++ b/apps/image-labeler/src/features/projects-list/ProjectsList.module.css @@ -0,0 +1,29 @@ +.pageTitle { + font: var(--font-XL); + margin-bottom: var(--space-M); +} + +.project { + display: block; + margin-bottom: var(--space-M); + padding-block: var(--space-M); +} + +.project:not(:last-child) { + border-bottom: var(--border); +} + +.projectName { + font: var(--font-L); + text-decoration: underline; + margin-bottom: var(--space-S); +} + +.projectProperties { + display: flex; + gap: var(--space-M); +} + +.projectProperties > div { + max-width: 50vw; +} diff --git a/apps/image-labeler/src/features/projects-list/ProjectsList.tsx b/apps/image-labeler/src/features/projects-list/ProjectsList.tsx new file mode 100644 index 0000000000..bbd86604cc --- /dev/null +++ b/apps/image-labeler/src/features/projects-list/ProjectsList.tsx @@ -0,0 +1,53 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Link } from '@tanstack/react-router' +import { useGFWLogin, useGFWLoginRedirect } from '@globalfishingwatch/react-hooks/use-login' +import { Spinner } from '@globalfishingwatch/ui-components/spinner' +import { useGetLabellingProjectsListQuery } from '../../api/projects-list' +import styles from './ProjectsList.module.css' + +type LabellingProject = { + id: number + name: string + labels: string[] + bqQuery: string + bqTable: string + gcsThumbnails: string +} + +export function ProjectsList() { + const login = useGFWLogin() + useGFWLoginRedirect(login) + const { data, isLoading } = useGetLabellingProjectsListQuery({}, { skip: !login.logged }) + if (!login.logged || isLoading) { + return + } + return ( +
+

Labelling Projects

+ {data.entries.map((project: LabellingProject) => ( + +

{project.name}

+
+
+ + {project.labels.join(', ')} +
+ {/*
+ + {project.bqQuery} +
*/} +
+ + ))} +
+ ) +} + +export default ProjectsList diff --git a/apps/image-labeler/src/features/projects/Projects.tsx b/apps/image-labeler/src/features/projects/Projects.tsx deleted file mode 100644 index 35010f659e..0000000000 --- a/apps/image-labeler/src/features/projects/Projects.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { Link } from '@tanstack/react-router' -import { useGFWLogin, useGFWLoginRedirect } from '@globalfishingwatch/react-hooks/use-login' -import { Spinner } from '@globalfishingwatch/ui-components/spinner' -import styles from './projects.module.css' - -const tasks = [ - { id: 1, name: 'Task 1' }, - { id: 2, name: 'Task 2' }, -] - -export function App() { - const login = useGFWLogin() - useGFWLoginRedirect(login) - if (!login.logged) { - return - } - return ( -
-

Projects page

- {tasks.map((task) => ( -
- - {task.name} - -
- ))} -
- ) -} - -export default App diff --git a/apps/image-labeler/src/features/projects/projects.module.css b/apps/image-labeler/src/features/projects/projects.module.css deleted file mode 100644 index 7b88fbabf8..0000000000 --- a/apps/image-labeler/src/features/projects/projects.module.css +++ /dev/null @@ -1 +0,0 @@ -/* Your styles goes here. */ diff --git a/apps/image-labeler/src/features/tasks/Tasks.tsx b/apps/image-labeler/src/features/tasks/Tasks.tsx deleted file mode 100644 index bc0ebf2a4b..0000000000 --- a/apps/image-labeler/src/features/tasks/Tasks.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { getRouteApi } from '@tanstack/react-router' -import styles from './tasks.module.css' - -const route = getRouteApi('/tasks/$taskId') - -export function App() { - const { taskId } = route.useParams() - return

Your tasks: {taskId}

-} - -export default App diff --git a/apps/image-labeler/src/features/tasks/tasks.module.css b/apps/image-labeler/src/features/tasks/tasks.module.css deleted file mode 100644 index 7b88fbabf8..0000000000 --- a/apps/image-labeler/src/features/tasks/tasks.module.css +++ /dev/null @@ -1 +0,0 @@ -/* Your styles goes here. */ diff --git a/apps/image-labeler/src/main.module.css b/apps/image-labeler/src/main.module.css new file mode 100644 index 0000000000..4ec864bf2e --- /dev/null +++ b/apps/image-labeler/src/main.module.css @@ -0,0 +1,6 @@ +.app { + height: 100vh; + width: 100vw; + padding: var(--space-L); + background: var(--gradient); +} diff --git a/apps/image-labeler/src/main.tsx b/apps/image-labeler/src/main.tsx index addd688f3b..16c5087516 100644 --- a/apps/image-labeler/src/main.tsx +++ b/apps/image-labeler/src/main.tsx @@ -2,7 +2,14 @@ import React, { StrictMode } from 'react' import ReactDOM from 'react-dom/client' import { RouterProvider, createRouter } from '@tanstack/react-router' // Import the generated route tree +import { Provider } from 'react-redux' +import { configureStore } from '@reduxjs/toolkit' +import { projectsListApi } from './api/projects-list' import { routeTree } from './routeTree.gen' +import { projectApi } from './api/project' +import styles from './main.module.css' +import { taskApi } from './api/task' +import '../../../libs/ui-components/src/base.css' // Create a new router instance export const router = createRouter({ routeTree }) @@ -17,10 +24,27 @@ declare module '@tanstack/react-router' { // Render the app const rootElement = document.getElementById('app')! if (!rootElement?.innerHTML) { + const store = configureStore({ + reducer: { + [projectsListApi.reducerPath]: projectsListApi.reducer, + [projectApi.reducerPath]: projectApi.reducer, + [taskApi.reducerPath]: taskApi.reducer, + }, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware().concat([ + projectsListApi.middleware, + projectApi.middleware, + taskApi.middleware, + ]), + }) const root = ReactDOM.createRoot(rootElement) root.render( - + +
+ +
+
) } diff --git a/apps/image-labeler/src/routeTree.gen.ts b/apps/image-labeler/src/routeTree.gen.ts index f4758b231d..a3731bafe0 100644 --- a/apps/image-labeler/src/routeTree.gen.ts +++ b/apps/image-labeler/src/routeTree.gen.ts @@ -17,7 +17,7 @@ import { Route as rootRoute } from './routes/__root' // Create Virtual Routes const IndexLazyImport = createFileRoute('/')() -const TasksTaskIdLazyImport = createFileRoute('/tasks/$taskId')() +const ProjectProjectIdLazyImport = createFileRoute('/project/$projectId')() // Create/Update Routes @@ -26,10 +26,12 @@ const IndexLazyRoute = IndexLazyImport.update({ getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route)) -const TasksTaskIdLazyRoute = TasksTaskIdLazyImport.update({ - path: '/tasks/$taskId', +const ProjectProjectIdLazyRoute = ProjectProjectIdLazyImport.update({ + path: '/project/$projectId', getParentRoute: () => rootRoute, -} as any).lazy(() => import('./routes/tasks.$taskId.lazy').then((d) => d.Route)) +} as any).lazy(() => + import('./routes/project.$projectId.lazy').then((d) => d.Route), +) // Populate the FileRoutesByPath interface @@ -42,11 +44,11 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexLazyImport parentRoute: typeof rootRoute } - '/tasks/$taskId': { - id: '/tasks/$taskId' - path: '/tasks/$taskId' - fullPath: '/tasks/$taskId' - preLoaderRoute: typeof TasksTaskIdLazyImport + '/project/$projectId': { + id: '/project/$projectId' + path: '/project/$projectId' + fullPath: '/project/$projectId' + preLoaderRoute: typeof ProjectProjectIdLazyImport parentRoute: typeof rootRoute } } @@ -56,7 +58,7 @@ declare module '@tanstack/react-router' { export const routeTree = rootRoute.addChildren({ IndexLazyRoute, - TasksTaskIdLazyRoute, + ProjectProjectIdLazyRoute, }) /* prettier-ignore-end */ @@ -68,14 +70,14 @@ export const routeTree = rootRoute.addChildren({ "filePath": "__root.tsx", "children": [ "/", - "/tasks/$taskId" + "/project/$projectId" ] }, "/": { "filePath": "index.lazy.tsx" }, - "/tasks/$taskId": { - "filePath": "tasks.$taskId.lazy.tsx" + "/project/$projectId": { + "filePath": "project.$projectId.lazy.tsx" } } } diff --git a/apps/image-labeler/src/routes/index.lazy.tsx b/apps/image-labeler/src/routes/index.lazy.tsx index ca78de6202..a33e9c3502 100644 --- a/apps/image-labeler/src/routes/index.lazy.tsx +++ b/apps/image-labeler/src/routes/index.lazy.tsx @@ -1,5 +1,5 @@ import { createLazyFileRoute } from '@tanstack/react-router' -import Projects from '../features/projects/projects' +import Projects from '../features/projects-list/ProjectsList' export const Route = createLazyFileRoute('/')({ component: Projects, diff --git a/apps/image-labeler/src/routes/project.$projectId.lazy.tsx b/apps/image-labeler/src/routes/project.$projectId.lazy.tsx new file mode 100644 index 0000000000..0203b2457c --- /dev/null +++ b/apps/image-labeler/src/routes/project.$projectId.lazy.tsx @@ -0,0 +1,6 @@ +import { createLazyFileRoute } from '@tanstack/react-router' +import TasksComponent from '../features/project/Project' + +export const Route = createLazyFileRoute('/project/$projectId')({ + component: TasksComponent, +}) diff --git a/apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx b/apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx deleted file mode 100644 index e6152ece7c..0000000000 --- a/apps/image-labeler/src/routes/tasks.$taskId.lazy.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { createLazyFileRoute } from '@tanstack/react-router' -import TasksComponent from '../features/tasks/tasks' - -export const Route = createLazyFileRoute('/tasks/$taskId')({ - component: TasksComponent, -}) diff --git a/apps/image-labeler/vite.config.mts b/apps/image-labeler/vite.config.mts index fde5df82e4..bebd71808a 100644 --- a/apps/image-labeler/vite.config.mts +++ b/apps/image-labeler/vite.config.mts @@ -1,6 +1,7 @@ /// import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import svgr from 'vite-plugin-svgr' import { viteStaticCopy } from 'vite-plugin-static-copy' import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' import { TanStackRouterVite } from '@tanstack/router-vite-plugin' @@ -21,6 +22,7 @@ export default defineConfig({ plugins: [ react(), + svgr(), nxViteTsPaths(), TanStackRouterVite({ routesDirectory: './apps/image-labeler/src/routes', diff --git a/libs/ui-components/src/choice/Choice.tsx b/libs/ui-components/src/choice/Choice.tsx index c172013481..f1e7819568 100644 --- a/libs/ui-components/src/choice/Choice.tsx +++ b/libs/ui-components/src/choice/Choice.tsx @@ -15,7 +15,7 @@ type ActiveChoiceProperties = { interface ChoiceProps { options: ChoiceOption[] - activeOption: string + activeOption?: string disabled?: boolean onSelect?: (option: ChoiceOption, e: React.MouseEvent) => void size?: ButtonSize @@ -36,7 +36,7 @@ export function Choice({ label, infoTooltip, }: ChoiceProps) { - const activeOptionId = activeOption || options?.[0]?.id + const activeOptionId = activeOption const activeRef = useRef(null) const [activeElementProperties, setActiveElementProperties] = useState< @@ -115,7 +115,7 @@ export function Choice({ ) })} - {activeElementProperties && ( + {activeOption && activeElementProperties && (
Date: Wed, 5 Jun 2024 13:38:13 +0200 Subject: [PATCH 05/17] show unlabeled if user didn't confirm --- apps/image-labeler/src/features/project/Project.tsx | 3 +-- apps/image-labeler/src/features/project/Task.tsx | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/image-labeler/src/features/project/Project.tsx b/apps/image-labeler/src/features/project/Project.tsx index 424623d1e3..7d577627f8 100644 --- a/apps/image-labeler/src/features/project/Project.tsx +++ b/apps/image-labeler/src/features/project/Project.tsx @@ -1,6 +1,5 @@ import { getRouteApi } from '@tanstack/react-router' -import { useEffect, useMemo, useState } from 'react' -import { set } from 'lodash' +import { useEffect, useState } from 'react' import { Spinner } from '@globalfishingwatch/ui-components/spinner' import { useGetLabellingProjectTasksQuery } from '../../api/project' import styles from './Project.module.css' diff --git a/apps/image-labeler/src/features/project/Task.tsx b/apps/image-labeler/src/features/project/Task.tsx index 3e9c58d03b..85441e7a16 100644 --- a/apps/image-labeler/src/features/project/Task.tsx +++ b/apps/image-labeler/src/features/project/Task.tsx @@ -52,6 +52,7 @@ export function Task({ projectId, task, open, onFinishTask }: TaskProps) { return } if (e.key === 'Escape') { + setActiveOption(undefined) onFinishTask() return } @@ -66,7 +67,7 @@ export function Task({ projectId, task, open, onFinishTask }: TaskProps) { return () => { window.removeEventListener('keydown', handleKeyDown) } - }, [handleSubmit, open, options]) + }, [handleSubmit, onFinishTask, open, options]) const setOption = (option: ChoiceOption) => { setActiveOption(option.id) From f7e452e4d04043853c3078e0614d3438250b9643 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Wed, 5 Jun 2024 15:54:36 +0200 Subject: [PATCH 06/17] fix nginx PORT --- apps/image-labeler/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/image-labeler/nginx.conf b/apps/image-labeler/nginx.conf index 61df99eb29..9fd7aa5088 100644 --- a/apps/image-labeler/nginx.conf +++ b/apps/image-labeler/nginx.conf @@ -28,7 +28,7 @@ http { gzip_min_length 100; server { - listen 80; + listen 8080; root /usr/share/nginx/www/; location ~* ^/image-labeler/(.+\..+)$ { From 022ffe4065ceb428b6f9ed9fa17794b57562f8f7 Mon Sep 17 00:00:00 2001 From: j8seangel Date: Wed, 5 Jun 2024 16:04:26 +0200 Subject: [PATCH 07/17] fix port variable replacement --- apps/image-labeler/Dockerfile | 4 ++-- apps/image-labeler/nginx.conf | 2 +- apps/image-labeler/vite.config.mts | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/image-labeler/Dockerfile b/apps/image-labeler/Dockerfile index e29bb7d2cc..0579fb1ca4 100644 --- a/apps/image-labeler/Dockerfile +++ b/apps/image-labeler/Dockerfile @@ -18,7 +18,7 @@ FROM nginx:stable-alpine as production COPY ./nginx.conf /etc/nginx/nginx.conf # COPY --from=htpasswd /home/.htpasswd /home/.htpasswd # RUN cat /home/.htpasswd >> /etc/nginx/.htpasswd -# COPY ./entrypoint.sh entrypoint.sh +COPY ./entrypoint.sh entrypoint.sh COPY ./ /usr/share/nginx/www/ -# ENTRYPOINT ["./entrypoint.sh"] +ENTRYPOINT ["./entrypoint.sh"] diff --git a/apps/image-labeler/nginx.conf b/apps/image-labeler/nginx.conf index 9fd7aa5088..8c7c2edf2f 100644 --- a/apps/image-labeler/nginx.conf +++ b/apps/image-labeler/nginx.conf @@ -28,7 +28,7 @@ http { gzip_min_length 100; server { - listen 8080; + listen ${PORT}; root /usr/share/nginx/www/; location ~* ^/image-labeler/(.+\..+)$ { diff --git a/apps/image-labeler/vite.config.mts b/apps/image-labeler/vite.config.mts index bebd71808a..3157e45833 100644 --- a/apps/image-labeler/vite.config.mts +++ b/apps/image-labeler/vite.config.mts @@ -34,6 +34,10 @@ export default defineConfig({ src: 'nginx.conf', dest: '', }, + { + src: '../../config/entrypoint.sh', + dest: '', + }, ], }), ], From 28b27c8b96eeecee1fb1457659e1e223726883aa Mon Sep 17 00:00:00 2001 From: j8seangel Date: Wed, 5 Jun 2024 16:12:25 +0200 Subject: [PATCH 08/17] make the api-client bundle much smaller --- libs/api-client/src/utils/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/api-client/src/utils/search.ts b/libs/api-client/src/utils/search.ts index 0ed3cd9914..bd74f4f50c 100644 --- a/libs/api-client/src/utils/search.ts +++ b/libs/api-client/src/utils/search.ts @@ -1,4 +1,4 @@ -import { partition } from 'lodash' +import partition from 'lodash/partition' import type { JSX } from 'react' // Copied from ui-components to avoid circular dependencies From 6ae226b762968932a6347e1c42d5961591a884e8 Mon Sep 17 00:00:00 2001 From: satellitestudiodesign Date: Wed, 5 Jun 2024 16:27:40 +0200 Subject: [PATCH 09/17] load more tasks, keep scroll position and project info --- .../src/features/project/Project.module.css | 28 ++++++++++++++++ .../src/features/project/Project.tsx | 32 +++++++++++++++++-- .../src/features/project/Task.module.css | 9 ++++-- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/apps/image-labeler/src/features/project/Project.module.css b/apps/image-labeler/src/features/project/Project.module.css index 05484fdc67..34aee886ad 100644 --- a/apps/image-labeler/src/features/project/Project.module.css +++ b/apps/image-labeler/src/features/project/Project.module.css @@ -1,4 +1,32 @@ +.project { + display: flex; + flex-direction: column; +} + +.loadMoreButton { + margin-block: var(--space-L); + margin-inline: auto; + width: 30rem; +} + .pageTitle { font: var(--font-XL); margin-bottom: var(--space-M); } + +.projectInfo code { + background-color: var(--color-terthiary-blue); + line-height: 1; + font-weight: 500; + font-family: 'Courier New', Courier, monospace; +} + +.projectInfoItem { + margin-bottom: var(--space-S); +} + +.tasksTitle { + font: var(--font-L); + margin-top: var(--space-M); + margin-bottom: var(--space-S); +} diff --git a/apps/image-labeler/src/features/project/Project.tsx b/apps/image-labeler/src/features/project/Project.tsx index 7d577627f8..833141be7c 100644 --- a/apps/image-labeler/src/features/project/Project.tsx +++ b/apps/image-labeler/src/features/project/Project.tsx @@ -1,6 +1,7 @@ import { getRouteApi } from '@tanstack/react-router' import { useEffect, useState } from 'react' import { Spinner } from '@globalfishingwatch/ui-components/spinner' +import { Button } from '@globalfishingwatch/ui-components/button' import { useGetLabellingProjectTasksQuery } from '../../api/project' import styles from './Project.module.css' import Task, { LabellingTask } from './Task' @@ -29,11 +30,35 @@ export function Project() { (task) => task.id === activeTaskId ) setActiveTaskId((data?.entries as LabellingTask[])[currentIndex + 1]?.id) + console.log(window) + + window.scrollTo(0, window.scrollY + 71) + } + + const handleLoadMoreTasks = () => { + window.scrollTo(0, 0) + window.location.reload() } return ( -
-

Project: {projectId}

+
+

{data.metadata.name}

+
+
+ +
{data.metadata.bqTable}
+
+
+ + {data.metadata.bqQuery} +
+
+ +
{data.metadata.labels.join(', ')}
+
+
+ +

Tasks

{(data?.entries as LabellingTask[]).map((task, index) => ( ))} +
) } diff --git a/apps/image-labeler/src/features/project/Task.module.css b/apps/image-labeler/src/features/project/Task.module.css index 520e419dd4..88a8ad9d58 100644 --- a/apps/image-labeler/src/features/project/Task.module.css +++ b/apps/image-labeler/src/features/project/Task.module.css @@ -7,7 +7,7 @@ justify-content: space-between; } -.task:last-child { +.task:last-of-type { border-bottom: var(--border); } @@ -21,16 +21,21 @@ .images { display: flex; gap: var(--space-S); + transition: all 0.2s ease-in-out; + width: 100%; + max-width: 11rem; + opacity: 0.5; } .images img { width: 5rem; background-color: var(--color-terthiary-blue); + transition: all 0.2s ease-in-out; } .open .images { - width: 100%; max-width: 80vh; + opacity: 1; } .open .images img { From 4c22c5bb95e49620fd7b224b5c6191e40832a82b Mon Sep 17 00:00:00 2001 From: satellitestudiodesign Date: Wed, 5 Jun 2024 16:28:45 +0200 Subject: [PATCH 10/17] remove log --- apps/image-labeler/src/features/project/Project.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/image-labeler/src/features/project/Project.tsx b/apps/image-labeler/src/features/project/Project.tsx index 833141be7c..b29f35969e 100644 --- a/apps/image-labeler/src/features/project/Project.tsx +++ b/apps/image-labeler/src/features/project/Project.tsx @@ -30,8 +30,6 @@ export function Project() { (task) => task.id === activeTaskId ) setActiveTaskId((data?.entries as LabellingTask[])[currentIndex + 1]?.id) - console.log(window) - window.scrollTo(0, window.scrollY + 71) } From 33d1624e6f0d488048196f70aed97e84c8d08c2b Mon Sep 17 00:00:00 2001 From: j8seangel Date: Wed, 5 Jun 2024 17:41:02 +0200 Subject: [PATCH 11/17] handle logout --- apps/image-labeler/src/routes/__root.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/image-labeler/src/routes/__root.tsx b/apps/image-labeler/src/routes/__root.tsx index ba05c66359..801119e4c8 100644 --- a/apps/image-labeler/src/routes/__root.tsx +++ b/apps/image-labeler/src/routes/__root.tsx @@ -1,17 +1,33 @@ import { createRootRoute, Outlet } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/router-devtools' -import { Fragment } from 'react' +import { Fragment, useCallback } from 'react' +import { GFWAPI } from '@globalfishingwatch/api-client' import { Spinner } from '@globalfishingwatch/ui-components/spinner' import { useGFWLogin, useGFWLoginRedirect } from '@globalfishingwatch/react-hooks/use-login' +import { Button } from '@globalfishingwatch/ui-components/button' const RootComponent = () => { const login = useGFWLogin() useGFWLoginRedirect(login) + const handleLogoutClick = useCallback(() => { + GFWAPI.logout().then(() => window.location.reload()) + }, []) + if (!login.logged) { return } + const isAdmin = login.user?.groups.some((group) => group.toLowerCase() === 'admin-group') + if (login.logged && !isAdmin) { + return ( +
+ You need to be an admin to access + +
+ ) + } + return ( From adcaf2a594d362af676f702c0640bc8a8dbe275c Mon Sep 17 00:00:00 2001 From: j8seangel Date: Wed, 5 Jun 2024 18:06:19 +0200 Subject: [PATCH 12/17] active task to url query param --- apps/image-labeler/src/api/base.ts | 3 + apps/image-labeler/src/api/project.ts | 14 ++- .../src/features/project/Project.tsx | 88 +++++++++++++------ .../src/features/project/Task.module.css | 4 + .../src/features/project/Task.tsx | 39 +++++--- apps/image-labeler/src/routeTree.gen.ts | 14 ++- .../src/routes/project.$projectId.lazy.tsx | 6 -- .../src/routes/project.$projectId.tsx | 16 ++++ 8 files changed, 130 insertions(+), 54 deletions(-) delete mode 100644 apps/image-labeler/src/routes/project.$projectId.lazy.tsx create mode 100644 apps/image-labeler/src/routes/project.$projectId.tsx diff --git a/apps/image-labeler/src/api/base.ts b/apps/image-labeler/src/api/base.ts index 487e654fea..55242f4457 100644 --- a/apps/image-labeler/src/api/base.ts +++ b/apps/image-labeler/src/api/base.ts @@ -19,6 +19,9 @@ export const gfwBaseQuery = async ({ url, signal, body }) => { try { const data = await GFWAPI.fetch(baseUrl + url, { signal, method, body }) + if (!data) { + return { data: body } + } return { data } } catch (gfwApiError: any) { return { diff --git a/apps/image-labeler/src/api/project.ts b/apps/image-labeler/src/api/project.ts index d7bc779f49..b865fe299d 100644 --- a/apps/image-labeler/src/api/project.ts +++ b/apps/image-labeler/src/api/project.ts @@ -6,6 +6,11 @@ type LabellingProjectsApiParams = { limit: number } +type LabellingProjectsByIdApiParams = { + projectId: string + taskId: string +} + export const projectApi = createApi({ reducerPath: 'projectApi', baseQuery: gfwBaseQuery({ @@ -19,9 +24,16 @@ export const projectApi = createApi({ } }, }), + getLabellingProjectTasksById: builder.query({ + query: ({ projectId, taskId }: LabellingProjectsByIdApiParams) => { + return { + url: `/${projectId}/task/${taskId}`, + } + }, + }), }), }) // Export hooks for usage in functional components, which are // auto-generated based on the defined endpoints -export const { useGetLabellingProjectTasksQuery } = projectApi +export const { useGetLabellingProjectTasksQuery, useGetLabellingProjectTasksByIdQuery } = projectApi diff --git a/apps/image-labeler/src/features/project/Project.tsx b/apps/image-labeler/src/features/project/Project.tsx index b29f35969e..8c3957f00b 100644 --- a/apps/image-labeler/src/features/project/Project.tsx +++ b/apps/image-labeler/src/features/project/Project.tsx @@ -1,68 +1,104 @@ -import { getRouteApi } from '@tanstack/react-router' -import { useEffect, useState } from 'react' +import { getRouteApi, useNavigate } from '@tanstack/react-router' +import { useCallback, useEffect, useMemo } from 'react' +import uniqBy from 'lodash/uniqBy' import { Spinner } from '@globalfishingwatch/ui-components/spinner' import { Button } from '@globalfishingwatch/ui-components/button' -import { useGetLabellingProjectTasksQuery } from '../../api/project' +import { + useGetLabellingProjectTasksByIdQuery, + useGetLabellingProjectTasksQuery, +} from '../../api/project' import styles from './Project.module.css' import Task, { LabellingTask } from './Task' -const route = getRouteApi('/project/$projectId') +const routePath = '/project/$projectId' +const route = getRouteApi(routePath) export function Project() { const { projectId } = route.useParams() + const { activeTaskId } = route.useSearch() + const navigate = useNavigate({ from: routePath }) - const { data, isLoading } = useGetLabellingProjectTasksQuery({ projectId, limit: 25 }) + // eslint-disable-next-line react-hooks/exhaustive-deps + const initialActiveTaskId = useMemo(() => activeTaskId as string | undefined, []) - const [activeTaskId, setActiveTaskId] = useState() + const { data: taskData, isLoading: areTasksLoading } = useGetLabellingProjectTasksQuery({ + projectId, + limit: 25, + }) + const { data: activeTaskData, isLoading: isActiveTaskLoading } = + useGetLabellingProjectTasksByIdQuery( + { + projectId, + taskId: initialActiveTaskId as string, + }, + { skip: initialActiveTaskId === undefined } + ) - useEffect(() => { - if (!activeTaskId) { - setActiveTaskId(data?.entries[0]?.id) + const isLoading = areTasksLoading || isActiveTaskLoading + const data = useMemo(() => { + if (!activeTaskData) { + return taskData?.entries as LabellingTask[] } - }, [activeTaskId, data]) + return uniqBy([activeTaskData, ...(taskData?.entries || [])], 'id') as LabellingTask[] + }, [activeTaskData, taskData?.entries]) - if (isLoading || !data) { - return - } + const setActiveTaskId = useCallback( + (activeTaskId: string) => { + navigate({ search: { activeTaskId } }) + }, + [navigate] + ) - const setNextTask = () => { - const currentIndex = (data?.entries as LabellingTask[]).findIndex( - (task) => task.id === activeTaskId - ) - setActiveTaskId((data?.entries as LabellingTask[])[currentIndex + 1]?.id) - window.scrollTo(0, window.scrollY + 71) - } + const setNextTask = useCallback( + (taskId: string) => { + const currentIndex = data.findIndex((task) => task.id === taskId) + setActiveTaskId(data[currentIndex + 1]?.id) + window.scrollTo(0, window.scrollY + 71) + }, + [data, setActiveTaskId] + ) - const handleLoadMoreTasks = () => { + const handleLoadMoreTasks = useCallback(() => { window.scrollTo(0, 0) window.location.reload() + }, []) + + useEffect(() => { + if (!activeTaskId) { + setActiveTaskId(data?.[0]?.id) + } + }, [activeTaskId, data, setActiveTaskId]) + + if (isLoading || !data) { + return } return (
-

{data.metadata.name}

+

{taskData.metadata.name}

-
{data.metadata.bqTable}
+
{taskData.metadata.bqTable}
- {data.metadata.bqQuery} + {taskData.metadata.bqQuery}
-
{data.metadata.labels.join(', ')}
+
{taskData.metadata.labels.join(', ')}

Tasks

- {(data?.entries as LabellingTask[]).map((task, index) => ( + {data.map((task, index) => ( setActiveTaskId(task.id)} onFinishTask={setNextTask} /> ))} diff --git a/apps/image-labeler/src/features/project/Task.module.css b/apps/image-labeler/src/features/project/Task.module.css index 88a8ad9d58..8dfa47e7bd 100644 --- a/apps/image-labeler/src/features/project/Task.module.css +++ b/apps/image-labeler/src/features/project/Task.module.css @@ -7,6 +7,10 @@ justify-content: space-between; } +.task:not(.open) { + cursor: pointer; +} + .task:last-of-type { border-bottom: var(--border); } diff --git a/apps/image-labeler/src/features/project/Task.tsx b/apps/image-labeler/src/features/project/Task.tsx index 85441e7a16..71cc593f39 100644 --- a/apps/image-labeler/src/features/project/Task.tsx +++ b/apps/image-labeler/src/features/project/Task.tsx @@ -19,10 +19,11 @@ type TaskProps = { projectId: string task: LabellingTask open: boolean - onFinishTask: () => void + onClick?: () => void + onFinishTask: (taskId: string) => void } -export function Task({ projectId, task, open, onFinishTask }: TaskProps) { +export function Task({ projectId, task, open, onClick, onFinishTask }: TaskProps) { const options: ChoiceOption[] = useMemo( () => task.labels.map((label, index) => ({ @@ -36,24 +37,27 @@ export function Task({ projectId, task, open, onFinishTask }: TaskProps) { fixedCacheKey: [projectId, task.id].join(), }) + const setFinishedTask = useCallback(() => { + onFinishTask(task.id) + }, [onFinishTask, task.id]) + const handleSubmit = useCallback(() => { if (activeOption) { - console.log('activeOption:', activeOption) - onFinishTask() + setFinishedTask() setTask({ projectId, taskId: task.id, label: activeOption }) } - }, [activeOption, onFinishTask, projectId, setTask, task.id]) + }, [activeOption, setFinishedTask, projectId, setTask, task.id]) useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { - e.preventDefault() + // e.preventDefault() if (e.key === 'Enter') { handleSubmit() return } if (e.key === 'Escape') { setActiveOption(undefined) - onFinishTask() + setFinishedTask() return } const option = options[parseInt(e.key) - 1] @@ -65,16 +69,21 @@ export function Task({ projectId, task, open, onFinishTask }: TaskProps) { window.addEventListener('keydown', handleKeyDown) } return () => { - window.removeEventListener('keydown', handleKeyDown) + if (open) { + window.removeEventListener('keydown', handleKeyDown) + } } - }, [handleSubmit, onFinishTask, open, options]) + }, [handleSubmit, setFinishedTask, open, options, task.id]) const setOption = (option: ChoiceOption) => { setActiveOption(option.id) } return ( -
+
{task.thumbnails.map((thumbnail, index) => ( thumbnail @@ -82,9 +91,13 @@ export function Task({ projectId, task, open, onFinishTask }: TaskProps) {
{open ? (
- +
-