From a2ba679a1a46ca68f01e4757b4bc2a1bdcb2c02e Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Wed, 17 Sep 2025 16:30:10 +0200 Subject: [PATCH 01/29] Fix lockfile --- ui/package-lock.json | 1190 +++++++++++++++++++----------------------- 1 file changed, 525 insertions(+), 665 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index ef966bffe5..0d7967d2bc 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -2291,33 +2291,6 @@ "statuses": "^2.0.1" } }, - "node_modules/@bundled-es-modules/tough-cookie": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", - "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@types/tough-cookie": "^4.0.5", - "tough-cookie": "^4.1.4" - } - }, - "node_modules/@bundled-es-modules/tough-cookie/node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@csstools/color-helpers": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", @@ -2483,9 +2456,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", - "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ "ppc64" ], @@ -2500,9 +2473,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", - "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", "cpu": [ "arm" ], @@ -2517,9 +2490,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", - "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", "cpu": [ "arm64" ], @@ -2534,9 +2507,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", - "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", "cpu": [ "x64" ], @@ -2551,9 +2524,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", - "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -2568,9 +2541,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", - "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], @@ -2585,9 +2558,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", - "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], @@ -2602,9 +2575,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", - "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], @@ -2619,9 +2592,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", - "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], @@ -2636,9 +2609,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", - "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], @@ -2653,9 +2626,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", - "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ "ia32" ], @@ -2670,9 +2643,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", - "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ "loong64" ], @@ -2687,9 +2660,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", - "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ "mips64el" ], @@ -2704,9 +2677,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", - "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ "ppc64" ], @@ -2721,9 +2694,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", - "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ "riscv64" ], @@ -2738,9 +2711,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", - "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ "s390x" ], @@ -2755,9 +2728,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", - "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -2772,9 +2745,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", - "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], @@ -2789,9 +2762,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", - "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ "x64" ], @@ -2806,9 +2779,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", - "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ "arm64" ], @@ -2823,9 +2796,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", - "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ "x64" ], @@ -2840,9 +2813,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", - "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", "cpu": [ "arm64" ], @@ -2857,9 +2830,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", - "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ "x64" ], @@ -2874,9 +2847,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", - "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], @@ -2891,9 +2864,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", - "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], @@ -2908,9 +2881,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", - "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], @@ -3068,6 +3041,16 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3082,9 +3065,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", - "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", + "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", "dev": true, "license": "MIT", "engines": { @@ -3248,9 +3231,9 @@ } }, "node_modules/@ianvs/prettier-plugin-sort-imports": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.4.2.tgz", - "integrity": "sha512-KkVFy3TLh0OFzimbZglMmORi+vL/i2OFhEs5M07R9w0IwWAGpsNNyE4CY/2u0YoMF5bawKC2+8/fUH60nnNtjw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.7.0.tgz", + "integrity": "sha512-soa2bPUJAFruLL4z/CnMfSEKGznm5ebz29fIa9PxYtu8HHyLKNE1NXAs6dylfw1jn/ilEIfO2oLLN6uAafb7DA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3261,12 +3244,24 @@ "semver": "^7.5.2" }, "peerDependencies": { + "@prettier/plugin-oxc": "^0.0.4", "@vue/compiler-sfc": "2.7.x || 3.x", - "prettier": "2 || 3 || ^4.0.0-0" + "content-tag": "^4.0.0", + "prettier": "2 || 3 || ^4.0.0-0", + "prettier-plugin-ember-template-tag": "^2.1.0" }, "peerDependenciesMeta": { + "@prettier/plugin-oxc": { + "optional": true + }, "@vue/compiler-sfc": { "optional": true + }, + "content-tag": { + "optional": true + }, + "prettier-plugin-ember-template-tag": { + "optional": true } } }, @@ -3505,62 +3500,62 @@ } }, "node_modules/@module-federation/error-codes": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.14.0.tgz", - "integrity": "sha512-GGk+EoeSACJikZZyShnLshtq9E2eCrDWbRiB4QAFXCX4oYmGgFfzXlx59vMNwqTKPJWxkEGnPYacJMcr2YYjag==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.18.0.tgz", + "integrity": "sha512-Woonm8ehyVIUPXChmbu80Zj6uJkC0dD9SJUZ/wOPtO8iiz/m+dkrOugAuKgoiR6qH4F+yorWila954tBz4uKsQ==", "dev": true, "license": "MIT" }, "node_modules/@module-federation/runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.14.0.tgz", - "integrity": "sha512-kR3cyHw/Y64SEa7mh4CHXOEQYY32LKLK75kJOmBroLNLO7/W01hMNAvGBYTedS7hWpVuefPk1aFZioy3q2VLdQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.18.0.tgz", + "integrity": "sha512-+C4YtoSztM7nHwNyZl6dQKGUVJdsPrUdaf3HIKReg/GQbrt9uvOlUWo2NXMZ8vDAnf/QRrpSYAwXHmWDn9Obaw==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "0.14.0", - "@module-federation/runtime-core": "0.14.0", - "@module-federation/sdk": "0.14.0" + "@module-federation/error-codes": "0.18.0", + "@module-federation/runtime-core": "0.18.0", + "@module-federation/sdk": "0.18.0" } }, "node_modules/@module-federation/runtime-core": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.14.0.tgz", - "integrity": "sha512-fGE1Ro55zIFDp/CxQuRhKQ1pJvG7P0qvRm2N+4i8z++2bgDjcxnCKUqDJ8lLD+JfJQvUJf0tuSsJPgevzueD4g==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.18.0.tgz", + "integrity": "sha512-ZyYhrDyVAhUzriOsVfgL6vwd+5ebYm595Y13KeMf6TKDRoUHBMTLGQ8WM4TDj8JNsy7LigncK8C03fn97of0QQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "0.14.0", - "@module-federation/sdk": "0.14.0" + "@module-federation/error-codes": "0.18.0", + "@module-federation/sdk": "0.18.0" } }, "node_modules/@module-federation/runtime-tools": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.14.0.tgz", - "integrity": "sha512-y/YN0c2DKsLETE+4EEbmYWjqF9G6ZwgZoDIPkaQ9p0pQu0V4YxzWfQagFFxR0RigYGuhJKmSU/rtNoHq+qF8jg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.18.0.tgz", + "integrity": "sha512-fSga9o4t1UfXNV/Kh6qFvRyZpPp3EHSPRISNeyT8ZoTpzDNiYzhtw0BPUSSD8m6C6XQh2s/11rI4g80UY+d+hA==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "0.14.0", - "@module-federation/webpack-bundler-runtime": "0.14.0" + "@module-federation/runtime": "0.18.0", + "@module-federation/webpack-bundler-runtime": "0.18.0" } }, "node_modules/@module-federation/sdk": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.14.0.tgz", - "integrity": "sha512-lg/OWRsh18hsyTCamOOhEX546vbDiA2O4OggTxxH2wTGr156N6DdELGQlYIKfRdU/0StgtQS81Goc0BgDZlx9A==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.18.0.tgz", + "integrity": "sha512-Lo/Feq73tO2unjmpRfyyoUkTVoejhItXOk/h5C+4cistnHbTV8XHrW/13fD5e1Iu60heVdAhhelJd6F898Ve9A==", "dev": true, "license": "MIT" }, "node_modules/@module-federation/webpack-bundler-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.14.0.tgz", - "integrity": "sha512-POWS6cKBicAAQ3DNY5X7XEUSfOfUsRaBNxbuwEfSGlrkTE9UcWheO06QP2ndHi8tHQuUKcIHi2navhPkJ+k5xg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.18.0.tgz", + "integrity": "sha512-TEvErbF+YQ+6IFimhUYKK3a5wapD90d90sLsNpcu2kB3QGT7t4nIluE25duXuZDVUKLz86tEPrza/oaaCWTpvQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "0.14.0", - "@module-federation/sdk": "0.14.0" + "@module-federation/runtime": "0.18.0", + "@module-federation/sdk": "0.18.0" } }, "node_modules/@msw/playwright": { @@ -3622,16 +3617,16 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.5.tgz", + "integrity": "sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" } }, "node_modules/@nodelib/fs.scandir": { @@ -4019,13 +4014,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.54.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.2.tgz", - "integrity": "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==", + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.0.tgz", + "integrity": "sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.54.2" + "playwright": "1.55.0" }, "bin": { "playwright": "cli.js" @@ -4119,9 +4114,9 @@ } }, "node_modules/@react-aria/autocomplete": { - "version": "3.0.0-beta.5", - "resolved": "https://registry.npmjs.org/@react-aria/autocomplete/-/autocomplete-3.0.0-beta.5.tgz", - "integrity": "sha512-zYiVeKGYHStpBXS0mf51k14xkVunU/dFqxumfYXDiiyknxIDE4L1kN7XKo16nus3TkTmJtqBHJrWmzCfNkRd9g==", + "version": "3.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@react-aria/autocomplete/-/autocomplete-3.0.0-rc.2.tgz", + "integrity": "sha512-55KVj5FePFTHk8nWfUUNN8m7rBL+aSRE0CxHI2t8JG3uam3nY7jyuAJy34RBuDEdTsVlMO9Fri/1JragePC2dg==", "license": "Apache-2.0", "dependencies": { "@react-aria/combobox": "^3.12.5", @@ -8482,23 +8477,23 @@ ] }, "node_modules/@rsbuild/core": { - "version": "1.3.22", - "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.3.22.tgz", - "integrity": "sha512-FGB7m8Tn/uiOhvqk0lw+NRMyD+VYJ+eBqVfpn0X11spkJDiPWn8UkMRvfzCX4XFcNZwRKYuuKJaZK1DNU8UG+w==", + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.5.8.tgz", + "integrity": "sha512-neCNfVxOoE7DsqDB5m1hEwxCwaTRdF6g5Nxq21FaDpSg0TpAdwzYlhHDhaCcriTOP0WhdYBn4l0TRRLP3bPDQQ==", "dev": true, "license": "MIT", "dependencies": { - "@rspack/core": "1.3.12", + "@rspack/core": "1.5.5", "@rspack/lite-tapable": "~1.0.1", "@swc/helpers": "^0.5.17", - "core-js": "~3.42.0", - "jiti": "^2.4.2" + "core-js": "~3.45.1", + "jiti": "^2.5.1" }, "bin": { "rsbuild": "bin/rsbuild.js" }, "engines": { - "node": ">=16.10.0" + "node": ">=18.12.0" } }, "node_modules/@rsbuild/plugin-babel": { @@ -8522,13 +8517,13 @@ } }, "node_modules/@rsbuild/plugin-react": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-1.3.5.tgz", - "integrity": "sha512-L/GoHgJV4j+EQbI4KOhe5EscM0OHgnSat1eR0Nt5P3JZxpJV2ryO5Yfx5jElPWOkYZZCuk+EWhHWDQ4CkeC5BQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-1.4.0.tgz", + "integrity": "sha512-YhhOUOonJBjnKpUf7E4iXKidldPWAGmYBRtDjQgcSmW4tbW0DasFpNCqLn5870Q2Ly6oCU06sLv+8G597I36+w==", "dev": true, "license": "MIT", "dependencies": { - "@rspack/plugin-react-refresh": "~1.4.3", + "@rspack/plugin-react-refresh": "^1.5.0", "react-refresh": "^0.17.0" }, "peerDependencies": { @@ -8536,9 +8531,9 @@ } }, "node_modules/@rsbuild/plugin-sass": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@rsbuild/plugin-sass/-/plugin-sass-1.3.5.tgz", - "integrity": "sha512-nW60+iLmV6fkCaE25xpnppISNveAw9z9xySFFcaU2VcpKQ1bGfGns785jlYRGS10E684zG6tL+NIOBS01uPwhQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rsbuild/plugin-sass/-/plugin-sass-1.4.0.tgz", + "integrity": "sha512-2XcrXUwJftWsWURsvGKKXc7A4yEAUdVkw+K95Qrfmy5E5IfARik0Ko3TFB1828wdvhZ1OFLvDQEzONCIyQV1yg==", "dev": true, "license": "MIT", "dependencies": { @@ -8581,27 +8576,28 @@ } }, "node_modules/@rspack/binding": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.3.12.tgz", - "integrity": "sha512-4Ic8lV0+LCBfTlH5aIOujIRWZOtgmG223zC4L3o8WY/+ESAgpdnK6lSSMfcYgRanYLAy3HOmFIp20jwskMpbAg==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.5.tgz", + "integrity": "sha512-JkB943uBU0lABnKG/jdO+gg3/eeO9CEQMR/1dL6jSU9GTxaNf3XIVc05RhRC7qoVsiXuhSMMFxWyV0hyHxp2bA==", "dev": true, "license": "MIT", "optionalDependencies": { - "@rspack/binding-darwin-arm64": "1.3.12", - "@rspack/binding-darwin-x64": "1.3.12", - "@rspack/binding-linux-arm64-gnu": "1.3.12", - "@rspack/binding-linux-arm64-musl": "1.3.12", - "@rspack/binding-linux-x64-gnu": "1.3.12", - "@rspack/binding-linux-x64-musl": "1.3.12", - "@rspack/binding-win32-arm64-msvc": "1.3.12", - "@rspack/binding-win32-ia32-msvc": "1.3.12", - "@rspack/binding-win32-x64-msvc": "1.3.12" + "@rspack/binding-darwin-arm64": "1.5.5", + "@rspack/binding-darwin-x64": "1.5.5", + "@rspack/binding-linux-arm64-gnu": "1.5.5", + "@rspack/binding-linux-arm64-musl": "1.5.5", + "@rspack/binding-linux-x64-gnu": "1.5.5", + "@rspack/binding-linux-x64-musl": "1.5.5", + "@rspack/binding-wasm32-wasi": "1.5.5", + "@rspack/binding-win32-arm64-msvc": "1.5.5", + "@rspack/binding-win32-ia32-msvc": "1.5.5", + "@rspack/binding-win32-x64-msvc": "1.5.5" } }, "node_modules/@rspack/binding-darwin-arm64": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.3.12.tgz", - "integrity": "sha512-8hKjVTBeWPqkMzFPNWIh72oU9O3vFy3e88wRjMPImDCXBiEYrKqGTTLd/J0SO+efdL3SBD1rX1IvdJpxCv6Yrw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.5.tgz", + "integrity": "sha512-Kg3ywEZHLX+aROfTQ5tMOv+Ud+8b4jk8ruUgsi0W8oBkEkR5xBdhFa9vcf6pzy+gfoLCnEI68U9i8ttm+G0csA==", "cpu": [ "arm64" ], @@ -8613,9 +8609,9 @@ ] }, "node_modules/@rspack/binding-darwin-x64": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.3.12.tgz", - "integrity": "sha512-Sj4m+mCUxL7oCpdu7OmWT7fpBM7hywk5CM9RDc3D7StaBZbvNtNftafCrTZzTYKuZrKmemTh5SFzT5Tz7tf6GA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.5.5.tgz", + "integrity": "sha512-uoGTYnlYW8m47yiDCKvXOehhAOH12wlePJq4sbUbBoHmG07vbDw7fUqnvy2k8319NTVEpMJWGoKyisgI09/uMQ==", "cpu": [ "x64" ], @@ -8627,9 +8623,9 @@ ] }, "node_modules/@rspack/binding-linux-arm64-gnu": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.3.12.tgz", - "integrity": "sha512-7MuOxf3/Mhv4mgFdLTvgnt/J+VouNR65DEhorth+RZm3LEWojgoFEphSAMAvpvAOpYSS68Sw4SqsOZi719ia2w==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.5.5.tgz", + "integrity": "sha512-KgVN3TeUJ3iNwwOX3JGY4arvoLHX94eItJ4TeOSyetRiSJUrQI0evP16i5kIh+n+p7mVnXmfUS944Gl+uNsJmg==", "cpu": [ "arm64" ], @@ -8641,9 +8637,9 @@ ] }, "node_modules/@rspack/binding-linux-arm64-musl": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.3.12.tgz", - "integrity": "sha512-s6KKj20T9Z1bA8caIjU6EzJbwyDo1URNFgBAlafCT2UC6yX7flstDJJ38CxZacA9A2P24RuQK2/jPSZpWrTUFA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.5.5.tgz", + "integrity": "sha512-1gKthlCQinXtWar6Hl9Il6BQ/NgYBH0NVuUsjjf85ejD/cTPQENKyIpGvVa1rSIHSfnG/XujUbruHAeY9mEHCA==", "cpu": [ "arm64" ], @@ -8655,9 +8651,9 @@ ] }, "node_modules/@rspack/binding-linux-x64-gnu": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.3.12.tgz", - "integrity": "sha512-0w/sRREYbRgHgWvs2uMEJSLfvzbZkPHUg6CMcYQGNVK6axYRot6jPyKetyFYA9pR5fB5rsXegpnFaZaVrRIK2g==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.5.5.tgz", + "integrity": "sha512-haPFg4M9GwpSI5g9BQhKUNdzCKDvFexIUkLiAHBjFU9iWQTEcI9VfYPixestOIwzUv7E34rHM+jAsmRGWdgmXw==", "cpu": [ "x64" ], @@ -8669,9 +8665,9 @@ ] }, "node_modules/@rspack/binding-linux-x64-musl": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.3.12.tgz", - "integrity": "sha512-jEdxkPymkRxbijDRsBGdhopcbGXiXDg59lXqIRkVklqbDmZ/O6DHm7gImmlx5q9FoWbz0gqJuOKBz4JqWxjWVA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.5.5.tgz", + "integrity": "sha512-oUny56JEkCZvIu4n8/P7IPLPNtJnL89EDhxHINH87XLBY3OOgo8JHELR11Zj9SFWiGNsRcLqi+Q78tWa0ligBQ==", "cpu": [ "x64" ], @@ -8682,10 +8678,24 @@ "linux" ] }, + "node_modules/@rspack/binding-wasm32-wasi": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.5.5.tgz", + "integrity": "sha512-tRgxBgIXaBKBH/0KlwvyqbIMqQrg8jKOyFOEQseEE7Oqs2M9KkJ7Vp5QN11u3NvZ9nz5GbZxmVGBMkdj9Gth1w==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.5" + } + }, "node_modules/@rspack/binding-win32-arm64-msvc": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.3.12.tgz", - "integrity": "sha512-ZRvUCb3TDLClAqcTsl/o9UdJf0B5CgzAxgdbnYJbldyuyMeTUB4jp20OfG55M3C2Nute2SNhu2bOOp9Se5Ongw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.5.5.tgz", + "integrity": "sha512-wGWd2yluoFdQgtkIbny6FoHnzahTk+o9RzrptjeS1u/NV1lKrWzmWhwZojMGOUqPiaukZKaziOEo7gpRn2XbEQ==", "cpu": [ "arm64" ], @@ -8697,9 +8707,9 @@ ] }, "node_modules/@rspack/binding-win32-ia32-msvc": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.3.12.tgz", - "integrity": "sha512-1TKPjuXStPJr14f3ZHuv40Xc/87jUXx10pzVtrPnw+f3hckECHrbYU/fvbVzZyuXbsXtkXpYca6ygCDRJAoNeQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.5.5.tgz", + "integrity": "sha512-Ikml8AQkzjPCG24vTO4pG2bpJ8vp93jVEgo9X9uYjO2vQbIp5QSOmeZOTM7tXCf8AfTfHEF/yAdE/pR/+tXXGQ==", "cpu": [ "ia32" ], @@ -8711,9 +8721,9 @@ ] }, "node_modules/@rspack/binding-win32-x64-msvc": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.3.12.tgz", - "integrity": "sha512-lCR0JfnYKpV+a6r2A2FdxyUKUS4tajePgpPJN5uXDgMGwrDtRqvx+d0BHhwjFudQVJq9VVbRaL89s2MQ6u+xYw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.5.5.tgz", + "integrity": "sha512-m2059ms0i/GIQGWTlZ5GI6SWpuMFAPMsWlhXLk2LZRIydhi+N/YPkmc33lFRTlDA3QpKDCvowvCvIIA7g6WSlg==", "cpu": [ "x64" ], @@ -8725,19 +8735,18 @@ ] }, "node_modules/@rspack/core": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.3.12.tgz", - "integrity": "sha512-mAPmV4LPPRgxpouUrGmAE4kpF1NEWJGyM5coebsjK/zaCMSjw3mkdxiU2b5cO44oIi0Ifv5iGkvwbdrZOvMyFA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.5.5.tgz", + "integrity": "sha512-AOIuMktK6X/xHAjJ/0QJ2kbSkILXj641GCPE+EOfWO27ODA8fHPArKbyz5AVGVePV3aUfEo2VFcsNzP67VBEPA==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime-tools": "0.14.0", - "@rspack/binding": "1.3.12", - "@rspack/lite-tapable": "1.0.1", - "caniuse-lite": "^1.0.30001718" + "@module-federation/runtime-tools": "0.18.0", + "@rspack/binding": "1.5.5", + "@rspack/lite-tapable": "1.0.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.12.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" @@ -8759,9 +8768,9 @@ } }, "node_modules/@rspack/plugin-react-refresh": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.4.3.tgz", - "integrity": "sha512-wZx4vWgy5oMEvgyNGd/oUKcdnKaccYWHCRkOqTdAPJC3WcytxhTX+Kady8ERurSBiLyQpoMiU3Iyd+F1Y2Arbw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.5.1.tgz", + "integrity": "sha512-GT3KV1GSmIXO8dQg6taNf9AuZ8XHEs8cZqRn5mC2GT6DPCvUA/ZKezIGsHTyH+HMEbJnJ/T8yYeJnvnzuUcqAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9142,13 +9151,13 @@ } }, "node_modules/@tanstack/eslint-plugin-query": { - "version": "5.78.0", - "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.78.0.tgz", - "integrity": "sha512-hYkhWr3UP0CkAsn/phBVR98UQawbw8CmTSgWtdgEBUjI60/GBaEIkpgi/Bp/2I8eIDK4+vdY7ac6jZx+GR+hEQ==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.89.0.tgz", + "integrity": "sha512-vz8TEuw9GO0xXIdreMpcofvOY17T3cjgob9bSFln8yQsKsbsUvtpvV3F8pVC3tZEDq0IwO++3/e0/+7YKEarNA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.18.1" + "@typescript-eslint/utils": "^8.37.0" }, "funding": { "type": "github", @@ -9159,9 +9168,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.80.12", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.80.12.tgz", - "integrity": "sha512-Cy+l+jNuII87oGpzkJ+nGDydzWJeq+gDr72lGURHXjD0UqZh5yRXcLg0Ix7jG+0Tn/ayGnR9+yph7Vbf1j8QZA==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.89.0.tgz", + "integrity": "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==", "license": "MIT", "funding": { "type": "github", @@ -9169,12 +9178,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.80.12", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.80.12.tgz", - "integrity": "sha512-hCtE5hw4rSqMcHSlkVLhM6jXy55rQsCE8qmgLq2MIqf/r4dRFrVlSqMczmO5w0ZQMYWeeHCYMrdRxtadajQK/Q==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz", + "integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.80.12" + "@tanstack/query-core": "5.89.0" }, "funding": { "type": "github", @@ -9185,9 +9194,9 @@ } }, "node_modules/@tauri-apps/cli": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.6.2.tgz", - "integrity": "sha512-s1/eyBHxk0wG1blLeOY2IDjgZcxVrkxU5HFL8rNDwjYGr0o7yr3RAtwmuUPhz13NO+xGAL1bJZaLFBdp+5joKg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.8.4.tgz", + "integrity": "sha512-ejUZBzuQRcjFV+v/gdj/DcbyX/6T4unZQjMSBZwLzP/CymEjKcc2+Fc8xTORThebHDUvqoXMdsCZt8r+hyN15g==", "dev": true, "license": "Apache-2.0 OR MIT", "bin": { @@ -9201,23 +9210,23 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.6.2", - "@tauri-apps/cli-darwin-x64": "2.6.2", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.6.2", - "@tauri-apps/cli-linux-arm64-gnu": "2.6.2", - "@tauri-apps/cli-linux-arm64-musl": "2.6.2", - "@tauri-apps/cli-linux-riscv64-gnu": "2.6.2", - "@tauri-apps/cli-linux-x64-gnu": "2.6.2", - "@tauri-apps/cli-linux-x64-musl": "2.6.2", - "@tauri-apps/cli-win32-arm64-msvc": "2.6.2", - "@tauri-apps/cli-win32-ia32-msvc": "2.6.2", - "@tauri-apps/cli-win32-x64-msvc": "2.6.2" + "@tauri-apps/cli-darwin-arm64": "2.8.4", + "@tauri-apps/cli-darwin-x64": "2.8.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.8.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.8.4", + "@tauri-apps/cli-linux-arm64-musl": "2.8.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.8.4", + "@tauri-apps/cli-linux-x64-gnu": "2.8.4", + "@tauri-apps/cli-linux-x64-musl": "2.8.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.8.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.8.4", + "@tauri-apps/cli-win32-x64-msvc": "2.8.4" } }, "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.6.2.tgz", - "integrity": "sha512-YlvT+Yb7u2HplyN2Cf/nBplCQARC/I4uedlYHlgtxg6rV7xbo9BvG1jLOo29IFhqA2rOp5w1LtgvVGwsOf2kxw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.8.4.tgz", + "integrity": "sha512-BKu8HRkYV01SMTa7r4fLx+wjgtRK8Vep7lmBdHDioP6b8XH3q2KgsAyPWfEZaZIkZ2LY4SqqGARaE9oilNe0oA==", "cpu": [ "arm64" ], @@ -9232,9 +9241,9 @@ } }, "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.6.2.tgz", - "integrity": "sha512-21gdPWfv1bP8rkTdCL44in70QcYcPaDM70L+y78N8TkBuC+/+wqnHcwwjzb+mUyck6UoEw2DORagSI/oKKUGJw==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.8.4.tgz", + "integrity": "sha512-imb9PfSd/7G6VAO7v1bQ2A3ZH4NOCbhGJFLchxzepGcXf9NKkfun157JH9mko29K6sqAwuJ88qtzbKCbWJTH9g==", "cpu": [ "x64" ], @@ -9249,9 +9258,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.6.2.tgz", - "integrity": "sha512-MW8Y6HqHS5yzQkwGoLk/ZyE1tWpnz/seDoY4INsbvUZdknuUf80yn3H+s6eGKtT/0Bfqon/W9sY7pEkgHRPQgA==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.8.4.tgz", + "integrity": "sha512-Ml215UnDdl7/fpOrF1CNovym/KjtUbCuPgrcZ4IhqUCnhZdXuphud/JT3E8X97Y03TZ40Sjz8raXYI2ET0exzw==", "cpu": [ "arm" ], @@ -9266,9 +9275,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.6.2.tgz", - "integrity": "sha512-9PdINTUtnyrnQt9hvC4y1m0NoxKSw/wUB9OTBAQabPj8WLAdvySWiUpEiqJjwLhlu4T6ltXZRpNTEzous3/RXg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.8.4.tgz", + "integrity": "sha512-pbcgBpMyI90C83CxE5REZ9ODyIlmmAPkkJXtV398X3SgZEIYy5TACYqlyyv2z5yKgD8F8WH4/2fek7+jH+ZXAw==", "cpu": [ "arm64" ], @@ -9283,9 +9292,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.6.2.tgz", - "integrity": "sha512-LrcJTRr7FrtQlTDkYaRXIGo/8YU/xkWmBPC646WwKNZ/S6yqCiDcOMoPe7Cx4ZvcG6sK6LUCLQMfaSNEL7PT0A==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.8.4.tgz", + "integrity": "sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw==", "cpu": [ "arm64" ], @@ -9300,9 +9309,9 @@ } }, "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.6.2.tgz", - "integrity": "sha512-GnTshO/BaZ9KGIazz2EiFfXGWgLur5/pjqklRA/ck42PGdUQJhV/Ao7A7TdXPjqAzpFxNo6M/Hx0GCH2iMS7IA==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.8.4.tgz", + "integrity": "sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ==", "cpu": [ "riscv64" ], @@ -9317,9 +9326,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.6.2.tgz", - "integrity": "sha512-QDG3WeJD6UJekmrtVPCJRzlKgn9sGzhvD58oAw5gIU+DRovgmmG2U1jH9fS361oYGjWWO7d/KM9t0kugZzi4lQ==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.8.4.tgz", + "integrity": "sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw==", "cpu": [ "x64" ], @@ -9334,9 +9343,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.6.2.tgz", - "integrity": "sha512-TNVTDDtnWzuVqWBFdZ4+8ZTg17tc21v+CT5XBQ+KYCoYtCrIaHpW04fS5Tmudi+vYdBwoPDfwpKEB6LhCeFraQ==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.8.4.tgz", + "integrity": "sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA==", "cpu": [ "x64" ], @@ -9351,9 +9360,9 @@ } }, "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.6.2.tgz", - "integrity": "sha512-z77C1oa/hMLO/jM1JF39tK3M3v9nou7RsBnQoOY54z5WPcpVAbS0XdFhXB7sSN72BOiO3moDky9lQANQz6L3CA==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.8.4.tgz", + "integrity": "sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w==", "cpu": [ "arm64" ], @@ -9368,9 +9377,9 @@ } }, "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.6.2.tgz", - "integrity": "sha512-TmD8BbzbjluBw8+QEIWUVmFa9aAluSkT1N937n1mpYLXcPbTpbunqRFiIznTwupoJNJIdtpF/t7BdZDRh5rrcg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.8.4.tgz", + "integrity": "sha512-yj7WDxkL1t9Uzr2gufQ1Hl7hrHuFKTNEOyascbc109EoiAqCp0tgZ2IykQqOZmZOHU884UAWI1pVMqBhS/BfhA==", "cpu": [ "ia32" ], @@ -9385,9 +9394,9 @@ } }, "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.6.2.tgz", - "integrity": "sha512-ItB8RCKk+nCmqOxOvbNtltz6x1A4QX6cSM21kj3NkpcnjT9rHSMcfyf8WVI2fkoMUJR80iqCblUX6ARxC3lj6w==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.8.4.tgz", + "integrity": "sha512-XuvGB4ehBdd7QhMZ9qbj/8icGEatDuBNxyYHbLKsTYh90ggUlPa/AtaqcC1Fo69lGkTmq9BOKrs1aWSi7xDonA==", "cpu": [ "x64" ], @@ -9422,9 +9431,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.4.tgz", - "integrity": "sha512-xDXgLjVunjHqczScfkCJ9iyjdNOVHvvCdqHSSxwM9L0l/wHkTRum67SDc020uAlCoqktJplgO2AAQeLP1wgqDQ==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.8.0.tgz", + "integrity": "sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9432,7 +9441,6 @@ "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", "picocolors": "^1.1.1", "redent": "^3.0.0" }, @@ -9697,12 +9705,12 @@ } }, "node_modules/@types/node": { - "version": "24.0.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.15.tgz", - "integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==", + "version": "24.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.1.tgz", + "integrity": "sha512-/SQdmUP2xa+1rdx7VwB9yPq8PaKej8TD5cQ+XfKDPWWC+VDJU4rvVVagXqKUzhKjtFoNA8rXDJAkCxQPAe00+Q==", "license": "MIT", "dependencies": { - "undici-types": "~7.8.0" + "undici-types": "~7.12.0" } }, "node_modules/@types/parse-json": { @@ -9739,13 +9747,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", @@ -9754,17 +9755,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz", - "integrity": "sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.0.tgz", + "integrity": "sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.31.1", - "@typescript-eslint/type-utils": "8.31.1", - "@typescript-eslint/utils": "8.31.1", - "@typescript-eslint/visitor-keys": "8.31.1", + "@typescript-eslint/scope-manager": "8.44.0", + "@typescript-eslint/type-utils": "8.44.0", + "@typescript-eslint/utils": "8.44.0", + "@typescript-eslint/visitor-keys": "8.44.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -9778,123 +9779,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz", - "integrity": "sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.31.1", - "@typescript-eslint/visitor-keys": "8.31.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.1.tgz", - "integrity": "sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz", - "integrity": "sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.31.1", - "@typescript-eslint/visitor-keys": "8.31.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.1.tgz", - "integrity": "sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.31.1", - "@typescript-eslint/types": "8.31.1", - "@typescript-eslint/typescript-estree": "8.31.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { + "@typescript-eslint/parser": "^8.44.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz", - "integrity": "sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.31.1", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { @@ -9981,14 +9868,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz", - "integrity": "sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.0.tgz", + "integrity": "sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.31.1", - "@typescript-eslint/utils": "8.31.1", + "@typescript-eslint/types": "8.44.0", + "@typescript-eslint/typescript-estree": "8.44.0", + "@typescript-eslint/utils": "8.44.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -10001,7 +9889,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { @@ -10443,6 +10331,19 @@ "node": ">=14.0.0" } }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", @@ -11589,9 +11490,9 @@ } }, "node_modules/core-js": { - "version": "3.42.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", - "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", + "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -12219,9 +12120,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.221", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.221.tgz", - "integrity": "sha512-/1hFJ39wkW01ogqSyYoA4goOXOtMRy6B+yvA1u42nnsEGtHzIzmk93aPISumVQeblj47JUHLC9coCjUxb1EvtQ==", + "version": "1.5.220", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.220.tgz", + "integrity": "sha512-TWXijEwR1ggr4BdAKrb1nMNqYLTx1/4aD1fkeZU+FVJGTKu53/T7UyHKXlqEX3Ub02csyHePbHmkvnrjcaYzMA==", "dev": true, "license": "ISC" }, @@ -12460,9 +12361,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", - "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -12473,32 +12374,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.10", - "@esbuild/android-arm": "0.25.10", - "@esbuild/android-arm64": "0.25.10", - "@esbuild/android-x64": "0.25.10", - "@esbuild/darwin-arm64": "0.25.10", - "@esbuild/darwin-x64": "0.25.10", - "@esbuild/freebsd-arm64": "0.25.10", - "@esbuild/freebsd-x64": "0.25.10", - "@esbuild/linux-arm": "0.25.10", - "@esbuild/linux-arm64": "0.25.10", - "@esbuild/linux-ia32": "0.25.10", - "@esbuild/linux-loong64": "0.25.10", - "@esbuild/linux-mips64el": "0.25.10", - "@esbuild/linux-ppc64": "0.25.10", - "@esbuild/linux-riscv64": "0.25.10", - "@esbuild/linux-s390x": "0.25.10", - "@esbuild/linux-x64": "0.25.10", - "@esbuild/netbsd-arm64": "0.25.10", - "@esbuild/netbsd-x64": "0.25.10", - "@esbuild/openbsd-arm64": "0.25.10", - "@esbuild/openbsd-x64": "0.25.10", - "@esbuild/openharmony-arm64": "0.25.10", - "@esbuild/sunos-x64": "0.25.10", - "@esbuild/win32-arm64": "0.25.10", - "@esbuild/win32-ia32": "0.25.10", - "@esbuild/win32-x64": "0.25.10" + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, "node_modules/escalade": { @@ -12525,20 +12426,20 @@ } }, "node_modules/eslint": { - "version": "9.25.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", - "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "version": "9.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", + "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.13.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", + "@eslint/js": "9.35.0", + "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -12585,6 +12486,31 @@ } } }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -12608,18 +12534,18 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.3.5.tgz", - "integrity": "sha512-QGwhLrwn/WGOsdrWvjhm9n8BvKN/Wr41SQERMV7DQ2hm9+Ozas39CyQUxum///l2G2vefQVr7VbIaCFS5h9g5g==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", + "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", "dev": true, "license": "ISC", "dependencies": { "debug": "^4.4.0", "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.3" + "stable-hash-x": "^0.2.0", + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.11" }, "engines": { "node": "^16.17.0 || >=18.6.0" @@ -13047,6 +12973,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -13836,9 +13772,9 @@ } }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -14923,16 +14859,15 @@ "license": "MIT" }, "node_modules/msw": { - "version": "2.10.5", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.10.5.tgz", - "integrity": "sha512-0EsQCrCI1HbhpBWd89DvmxY6plmvrM96b0sCIztnvcNHQbXn5vqwm1KlXslo6u4wN9LFGLC1WFjjgljcQhe40A==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.2.tgz", + "integrity": "sha512-MI54hLCsrMwiflkcqlgYYNJJddY5/+S0SnONvhv1owOplvqohKSQyGejpNdUGyCwgs4IH7PqaNbPw/sKOEze9Q==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@bundled-es-modules/cookie": "^2.0.1", "@bundled-es-modules/statuses": "^1.0.1", - "@bundled-es-modules/tough-cookie": "^0.1.6", "@inquirer/confirm": "^5.0.0", "@mswjs/interceptors": "^0.39.1", "@open-draft/deferred-promise": "^2.2.0", @@ -14945,7 +14880,9 @@ "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", + "rettime": "^0.7.0", "strict-event-emitter": "^0.5.1", + "tough-cookie": "^6.0.0", "type-fest": "^4.26.1", "yargs": "^17.7.2" }, @@ -14967,6 +14904,39 @@ } } }, + "node_modules/msw/node_modules/tldts": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.14.tgz", + "integrity": "sha512-lMNHE4aSI3LlkMUMicTmAG3tkkitjOQGDTFboPJwAg2kJXKP1ryWEyqujktg5qhrFZOkk5YFzgkxg3jErE+i5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.14" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/msw/node_modules/tldts-core": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.14.tgz", + "integrity": "sha512-viZGNK6+NdluOJWwTO9olaugx0bkKhscIdriQQ+lNNhwitIKvb+SvhbYgnCz6j9p7dX3cJntt4agQAKMXLjJ5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/msw/node_modules/tough-cookie": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", + "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", @@ -15257,9 +15227,9 @@ } }, "node_modules/openapi-msw": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/openapi-msw/-/openapi-msw-1.2.0.tgz", - "integrity": "sha512-Ksm8xG8Lm8O9IU0rC7d1rQ0kcqYf5+qW+iz94G5fuZ/tfinjzSPnhBEwRj7dStvlqCMFQEriVWt7rplbvg0zqA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/openapi-msw/-/openapi-msw-1.3.0.tgz", + "integrity": "sha512-qRe9zEHSYRi9s9EimTF/IxsG6yvEilkg+pn4Y0QldkuIx+13HcjoNACEumVdpc87nR5AtPErbzuuWFv+cw6fhg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -15287,17 +15257,17 @@ "license": "MIT" }, "node_modules/openapi-typescript": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.8.0.tgz", - "integrity": "sha512-1EeVWmDzi16A+siQlo/SwSGIT7HwaFAVjvMA7/jG5HMLSnrUOzPL7uSTRZZa4v/LCRxHTApHKtNY6glApEoiUQ==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.9.1.tgz", + "integrity": "sha512-9gJtoY04mk6iPMbToPjPxEAtfXZ0dTsMZtsgUI8YZta0btPPig9DJFP4jlerQD/7QOwYgb0tl+zLUpDf7vb7VA==", "dev": true, "license": "MIT", "dependencies": { - "@redocly/openapi-core": "^1.34.3", + "@redocly/openapi-core": "^1.34.5", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.3.0", - "supports-color": "^10.0.0", + "supports-color": "^10.1.0", "yargs-parser": "^21.1.1" }, "bin": { @@ -15596,13 +15566,13 @@ "license": "MIT" }, "node_modules/playwright": { - "version": "1.54.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz", - "integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==", + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.0.tgz", + "integrity": "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.54.2" + "playwright-core": "1.55.0" }, "bin": { "playwright": "cli.js" @@ -15615,9 +15585,9 @@ } }, "node_modules/playwright-core": { - "version": "1.54.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz", - "integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==", + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz", + "integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -15696,9 +15666,9 @@ } }, "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -15780,19 +15750,6 @@ "node": ">=12.0.0" } }, - "node_modules/psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "funding": { - "url": "https://github.com/sponsors/lupomontero" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -15803,13 +15760,6 @@ "node": ">=6" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true, - "license": "MIT" - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15909,56 +15859,39 @@ } }, "node_modules/react-aria-components": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.10.1.tgz", - "integrity": "sha512-Mllbk2pQax2EwlOJsXG4oTp6P7P33m82/47M9Os+zaGhSCqo2EilFvThxCFxhLa7ncjLV0ka6wFIYLmZiOcWxw==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.12.2.tgz", + "integrity": "sha512-BTA697VWy6Who9cpSbll447kqqpwxYvN6QF3/+AmXO+M+KgUXtPZAaNXu/9Sv2LdshU0zhIea4w27ZOt57UzPQ==", "license": "Apache-2.0", "dependencies": { "@internationalized/date": "^3.8.2", "@internationalized/string": "^3.2.7", - "@react-aria/autocomplete": "3.0.0-beta.5", - "@react-aria/collections": "3.0.0-rc.3", - "@react-aria/dnd": "^3.10.1", - "@react-aria/focus": "^3.20.5", - "@react-aria/interactions": "^3.25.3", - "@react-aria/live-announcer": "^3.4.3", - "@react-aria/overlays": "^3.27.3", - "@react-aria/ssr": "^3.9.9", - "@react-aria/toolbar": "3.0.0-beta.18", - "@react-aria/utils": "^3.29.1", - "@react-aria/virtualizer": "^4.1.7", - "@react-stately/autocomplete": "3.0.0-beta.2", - "@react-stately/layout": "^4.3.1", - "@react-stately/selection": "^3.20.3", - "@react-stately/table": "^3.14.3", - "@react-stately/utils": "^3.10.7", - "@react-stately/virtualizer": "^4.4.1", - "@react-types/form": "^3.7.13", - "@react-types/grid": "^3.3.3", - "@react-types/shared": "^3.30.0", - "@react-types/table": "^3.13.1", + "@react-aria/autocomplete": "3.0.0-rc.2", + "@react-aria/collections": "3.0.0-rc.7", + "@react-aria/dnd": "^3.11.2", + "@react-aria/focus": "^3.21.1", + "@react-aria/interactions": "^3.25.5", + "@react-aria/live-announcer": "^3.4.4", + "@react-aria/overlays": "^3.29.1", + "@react-aria/ssr": "^3.9.10", + "@react-aria/textfield": "^3.18.1", + "@react-aria/toolbar": "3.0.0-beta.20", + "@react-aria/utils": "^3.30.1", + "@react-aria/virtualizer": "^4.1.9", + "@react-stately/autocomplete": "3.0.0-beta.3", + "@react-stately/layout": "^4.5.0", + "@react-stately/selection": "^3.20.5", + "@react-stately/table": "^3.15.0", + "@react-stately/utils": "^3.10.8", + "@react-stately/virtualizer": "^4.4.3", + "@react-types/form": "^3.7.15", + "@react-types/grid": "^3.3.5", + "@react-types/shared": "^3.32.0", + "@react-types/table": "^3.13.3", "@swc/helpers": "^0.5.0", "client-only": "^0.0.1", - "react-aria": "^3.41.1", - "react-stately": "^3.39.0", - "use-sync-external-store": "^1.4.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/react-aria-components/node_modules/@react-aria/collections": { - "version": "3.0.0-rc.3", - "resolved": "https://registry.npmjs.org/@react-aria/collections/-/collections-3.0.0-rc.3.tgz", - "integrity": "sha512-TX6aAzK/FMTvT78LNdSSacKYDnfBWyW5WzxfoQiu/K/kbZVrYSrQaXFrGjkwGEhgmU0O1S4mupANMEgmgI3wlQ==", - "license": "Apache-2.0", - "dependencies": { - "@react-aria/interactions": "^3.25.3", - "@react-aria/ssr": "^3.9.9", - "@react-aria/utils": "^3.29.1", - "@react-types/shared": "^3.30.0", - "@swc/helpers": "^0.5.0", + "react-aria": "^3.43.2", + "react-stately": "^3.41.0", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { @@ -15966,23 +15899,6 @@ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/react-aria-components/node_modules/@react-aria/toolbar": { - "version": "3.0.0-beta.18", - "resolved": "https://registry.npmjs.org/@react-aria/toolbar/-/toolbar-3.0.0-beta.18.tgz", - "integrity": "sha512-P1fXhmTRBK4YvPQDzCY3XoZl+HiBADgvQ89jszxJ2jD4Qzs/E096ttCc+otZnbvRcoU27IxC2vWFInqK/bP31g==", - "license": "Apache-2.0", - "dependencies": { - "@react-aria/focus": "^3.20.5", - "@react-aria/i18n": "^3.12.10", - "@react-aria/utils": "^3.29.1", - "@react-types/shared": "^3.30.0", - "@swc/helpers": "^0.5.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, "node_modules/react-dom": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", @@ -16337,13 +16253,6 @@ "node": ">=0.10.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "license": "MIT" - }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -16395,6 +16304,13 @@ "node": ">=4" } }, + "node_modules/rettime": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz", + "integrity": "sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==", + "dev": true, + "license": "MIT" + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -17175,10 +17091,10 @@ "node": ">=0.10.0" } }, - "node_modules/stable-hash": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", - "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", "dev": true, "license": "MIT" }, @@ -17923,9 +17839,9 @@ } }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", "bin": { @@ -17937,15 +17853,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.31.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.1.tgz", - "integrity": "sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.44.0.tgz", + "integrity": "sha512-ib7mCkYuIzYonCq9XWF5XNw+fkj2zg629PSa9KNIQ47RXFF763S5BIX4wqz1+FLPogTZoiw8KmCiRPRa8bL3qw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.31.1", - "@typescript-eslint/parser": "8.31.1", - "@typescript-eslint/utils": "8.31.1" + "@typescript-eslint/eslint-plugin": "8.44.0", + "@typescript-eslint/parser": "8.44.0", + "@typescript-eslint/typescript-estree": "8.44.0", + "@typescript-eslint/utils": "8.44.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17956,7 +17873,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { @@ -18118,9 +18035,9 @@ } }, "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", + "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -18167,16 +18084,6 @@ "node": ">=4" } }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/unrs-resolver": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", @@ -18271,17 +18178,6 @@ "dev": true, "license": "MIT" }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/use-sync-external-store": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", @@ -18359,18 +18255,18 @@ } }, "node_modules/vite": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.7.tgz", - "integrity": "sha512-hc6LujN/EkJHmxeiDJMs0qBontZ1cdBvvoCbWhVjzUFTU329VRyOC46gHNSA8NcOC5yzCeXpwI40tieI3DEZqg==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", + "integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", - "fdir": "^6.4.6", + "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rollup": "^4.40.0", - "tinyglobby": "^0.2.14" + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" @@ -18457,13 +18353,13 @@ } }, "node_modules/vite-plugin-svgr": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.3.0.tgz", - "integrity": "sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.5.0.tgz", + "integrity": "sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==", "dev": true, "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.1.3", + "@rollup/pluginutils": "^5.2.0", "@svgr/core": "^8.1.0", "@svgr/plugin-jsx": "^8.1.0" }, @@ -19188,9 +19084,9 @@ } }, "packages/smart-tools/node_modules/@types/node": { - "version": "22.18.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz", - "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==", + "version": "22.18.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.5.tgz", + "integrity": "sha512-g9BpPfJvxYBXUWI9bV37j6d6LTMNQ88hPwdWWUeYZnMhlo66FIg9gCc1/DZb15QylJSKwOZjwrckvOTWpOiChg==", "dev": true, "license": "MIT", "dependencies": { @@ -19326,42 +19222,6 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, - "packages/smart-tools/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "packages/smart-tools/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "packages/smart-tools/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "packages/smart-tools/node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", From 5fa90938e20b4fd739aee66488d2b6f8d19fd786 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Wed, 17 Sep 2025 16:30:37 +0200 Subject: [PATCH 02/29] Enable SAM tool --- .../annotator/tools/annotator-tools.component.tsx | 3 ++- .../features/annotator/tools/tool-manager.component.tsx | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ui/src/features/annotator/tools/annotator-tools.component.tsx b/ui/src/features/annotator/tools/annotator-tools.component.tsx index 68bc122f8b..7c5b393986 100644 --- a/ui/src/features/annotator/tools/annotator-tools.component.tsx +++ b/ui/src/features/annotator/tools/annotator-tools.component.tsx @@ -17,7 +17,8 @@ const TASK_TOOL_CONFIG: Record = { ], segmentation: [ { type: 'selection', icon: Selector }, - // TODO: Add 'polygon' and 'sam' tools later + { type: 'sam', icon: BoundingBox }, + // TODO: Add 'polygon' tool later ], }; diff --git a/ui/src/features/annotator/tools/tool-manager.component.tsx b/ui/src/features/annotator/tools/tool-manager.component.tsx index 0254f5dfc9..2a3cb3269b 100644 --- a/ui/src/features/annotator/tools/tool-manager.component.tsx +++ b/ui/src/features/annotator/tools/tool-manager.component.tsx @@ -3,12 +3,20 @@ import { useAnnotator } from '../annotator-provider.component'; import { BoundingBoxTool } from './bounding-box-tool/bounding-box-tool.component'; +import { SegmentAnythingStateProvider } from './segment-anything-tool/segment-anything-state-provider.component'; +import { SegmentAnythingTool } from './segment-anything-tool/segment-anything-tool.component'; export const ToolManager = () => { const { activeTool } = useAnnotator(); if (activeTool === 'bounding-box') { return ; + } else if (activeTool === 'sam') { + return ( + + + + ); } return null; From 383e5dd68891eb2f16d88916deb1461b69970506 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Wed, 17 Sep 2025 16:32:27 +0200 Subject: [PATCH 03/29] Add SAM files --- .../hooks/use-segment-anything.hook.ts | 7 +- ...teractive-segmentation-point.component.tsx | 46 ++++ .../model-loading.component.tsx | 45 ++++ .../secondary-toolbar.component.tsx | 136 +++++++++++ ...ment-anything-state-provider.component.tsx | 136 +++++++++++ .../segment-anything-tool.component.tsx | 222 ++++++++++++++++++ .../segment-anything.interface.ts | 8 + .../segment-anything.module.scss | 24 ++ .../use-decoding-query.hook.ts | 77 ++++++ .../use-segment-anything-model.hook.ts | 115 +++++++++ .../use-single-stack-fn.hook.ts | 65 +++++ .../use-throttle-callback.hook.ts | 26 ++ 12 files changed, 905 insertions(+), 2 deletions(-) create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/model-loading.component.tsx create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/segment-anything.module.scss create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/use-single-stack-fn.hook.ts create mode 100644 ui/src/features/annotator/tools/segment-anything-tool/use-throttle-callback.hook.ts diff --git a/ui/src/features/annotator/hooks/use-segment-anything.hook.ts b/ui/src/features/annotator/hooks/use-segment-anything.hook.ts index 94c79ad3be..2da5d8bf91 100644 --- a/ui/src/features/annotator/hooks/use-segment-anything.hook.ts +++ b/ui/src/features/annotator/hooks/use-segment-anything.hook.ts @@ -4,15 +4,18 @@ import { useQuery } from '@tanstack/react-query'; import { wrap } from 'comlink'; -export const useSegmentAnythingWorkerQuery = () => { +export const useSegmentAnythingWorkerQuery = ( + algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'SEGMENT_ANYTHING_ENCODER' +) => { return useQuery({ - queryKey: ['workers', 'segment-anything'], + queryKey: ['workers', algorithmType], queryFn: async () => { const segmentAnythingWorker = wrap( new Worker(new URL('../webworkers/segment-anything.worker', import.meta.url), { type: 'module', }) ); + // @ts-expect-error build exists on every worker return segmentAnythingWorker.build(); }, diff --git a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx new file mode 100644 index 0000000000..cc4ecdaa69 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx @@ -0,0 +1,46 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { InteractiveAnnotationPoint } from './segment-anything.interface'; + +interface InteractiveSegmentationPointProps extends InteractiveAnnotationPoint { + isLoading: boolean; +} + +export const InteractiveSegmentationPoint = ({ x, y, positive, isLoading }: InteractiveSegmentationPointProps) => { + const fill = positive ? 'var(--brand-moss)' : 'var(--brand-coral-cobalt)'; + const radius = `1 / var(--zoom-scale)`; + + return ( + <> + + {isLoading && ( + + + + + + )} + + ); +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/model-loading.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/model-loading.component.tsx new file mode 100644 index 0000000000..8e881dc682 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/model-loading.component.tsx @@ -0,0 +1,45 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { Flex, Heading, View } from '@geti/ui'; + +import IntelBrandedLoadingGif from '../../../../assets/intel-loading.webp'; + +export const ModelLoading = ({ isLoadingModel }: { isLoadingModel: boolean }) => { + return ( + + + {/* eslint-disable-next-line jsx-a11y/img-redundant-alt */} + Extracting image features + + {isLoadingModel ? 'Loading image model' : 'Extracting image features'} + + + + ); +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx new file mode 100644 index 0000000000..2880c0fba3 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx @@ -0,0 +1,136 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { Button, Divider, Flex, Loading, Switch, Text, Tooltip, TooltipTrigger, useMediaQuery, View } from '@geti/ui'; +import { RightClick } from '@geti/ui/icons'; +import { isLargeSizeQuery } from '@geti/ui/theme'; + +import { useSegmentAnything } from './segment-anything-state-provider.component'; + +const INTERACTIVE_MODE_TOOLTIP = 'With this mode ON, edit preview by placing new positive or negative points. - SHIFT'; + +const RIGHT_CLICK_MODE_TOOLTIP = + 'With this mode ON, press left-click to place positive points and right-click to place negative points.'; + +// TODO: replace by actual tool settings +const toolSettings = { + interactiveMode: false, + rightClickMode: false, + maskOpacity: 0.5, +}; + +export const SecondaryToolbar = () => { + const isLargeSize = useMediaQuery(isLargeSizeQuery); + + const { points, isLoading, encodingQuery } = useSegmentAnything(); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const handleOnChange = (_value: number) => { + // TODO: Update tool settings + // updateToolSettings(ToolType.SegmentAnythingTool, { ...toolSettings, maskOpacity: value }); + }; + + const setToolSetting = (_data: unknown) => { + // TODO: Update tool settings + // updateToolSettings(ToolType.SegmentAnythingTool, { ...toolSettings, ...data }); + }; + + if (isLoading || encodingQuery.data === undefined) { + return ( + + {isLargeSize && ( + <> + Auto segmentation + + + )} + + + {isLoading ? 'Loading image model' : 'Extracting image features'} + + ); + } + + return ( + + {isLargeSize && ( + <> + Auto segmentation + + + )} + + + setToolSetting({ interactiveMode })} + height='100%' + aria-label='Interactive mode' + isDisabled={toolSettings.interactiveMode === true && points.length > 0} + > + Interactive mode + + {INTERACTIVE_MODE_TOOLTIP} + + + + + + + setToolSetting({ rightClickMode: val })} + height='100%' + aria-label='Right-click mode' + > + + Right-click mode + + + + + + + {RIGHT_CLICK_MODE_TOOLTIP} + + + + + + {/* + `${Math.round(100 * value)}%`} + label={'Mask opacity'} + ariaLabel='Mask opacity' + min={0} + max={1} + step={0.01} + onChange={handleOnChange} + value={toolSettings.maskOpacity} + /> + Adjust the opacity + */} + + {points.length > 0 && ( + <> + + + + + + + )} + + ); +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx new file mode 100644 index 0000000000..7b7fd4f3b7 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -0,0 +1,136 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { createContext, ReactNode, useContext, useEffect, useState } from 'react'; + +import { EncodingOutput } from '@geti/smart-tools/segment-anything'; +import { toast } from '@geti/ui'; +import { useQueryClient, UseQueryResult } from '@tanstack/react-query'; +import { isEmpty } from 'lodash-es'; + +import { Shape } from '../../types'; +import { InteractiveAnnotationPoint } from './segment-anything.interface'; +import { useDecodingMutation, useDecodingQuery, useDecodingQueryOptions } from './use-decoding-query.hook'; +import { useSegmentAnythingModel } from './use-segment-anything-model.hook'; +import { useSingleStackFn } from './use-single-stack-fn.hook'; + +interface SegmentAnythingState { + points: InteractiveAnnotationPoint[]; +} + +interface SegmentAnythingStateContextProps { + isProcessing: boolean; + isLoading: boolean; + + points: InteractiveAnnotationPoint[]; + addPoint: (point: InteractiveAnnotationPoint, keepPreviousPoints?: boolean) => void; + result: { shapes: Shape[] }; + handleCancelAnnotation: () => void; + handleConfirmAnnotation: () => void; + + encodingQuery: UseQueryResult; + decodingQueryFn: (points: InteractiveAnnotationPoint[]) => Promise; +} + +const SegmentAnythingStateContext = createContext(undefined); + +export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode }) => { + const [state, setState] = useState({ + points: [], + }); + const [_, setIsDrawing] = useState(false); + + const queryClient = useQueryClient(); + const { encodingQuery, decodingQueryFn, isLoading } = useSegmentAnythingModel(); + const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); + const decodingQueryOptions = useDecodingQueryOptions(state.points, throttledDecodingQueryFn); + const decodingQuery = useDecodingQuery(state.points, throttledDecodingQueryFn); + + useEffect(() => { + if (state.points.length > 0 && decodingQuery.data !== undefined && decodingQuery.data.length === 0) { + if (!decodingQuery.isPlaceholderData) { + toast({ + message: `Unable to segment object from the selected point${ + state.points.length > 1 ? 's' : '' + }. Press ESC to reset points.`, + type: 'warning', + }); + } + } + }, [decodingQuery.data, decodingQuery.isPlaceholderData, state.points]); + + const decodingMutation = useDecodingMutation(decodingQueryFn); + + const reset = async () => { + queryClient.removeQueries({ queryKey: decodingQueryOptions.queryKey }); + + setIsDrawing(false); + }; + + useEffect(() => { + return () => setIsDrawing(false); + }, [setIsDrawing]); + + const isProcessing = decodingQuery.isFetching; + + const hasResults = decodingQuery.data && !isEmpty(decodingQuery.data) && !isEmpty(state.points); + const outputShapes = decodingQuery.data ?? []; + const handleConfirmAnnotation = () => { + if (isProcessing) { + return; + } + + if (hasResults) { + // TODO: Add callback to add the shapes to the canvas + // addShapes(outputShapes); + } + + reset(); + }; + + const handleCancelAnnotation = () => { + if (!isProcessing) { + reset(); + } + }; + + const addPoint = (point: InteractiveAnnotationPoint, keepPreviousData = false) => { + setIsDrawing(true); + + if (keepPreviousData) { + setState((r) => ({ points: [...r.points, point] })); + } else { + decodingMutation.mutateAsync([point]).then(() => { + setIsDrawing(false); + }); + } + }; + + return ( + + {children} + + ); +}; + +export const useSegmentAnything = (): SegmentAnythingStateContextProps => { + const context = useContext(SegmentAnythingStateContext); + + if (context === undefined) { + throw new Error('useSegmentAnythingState must be used within a SegmentAnythingStateProvider'); + } + + return context; +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx new file mode 100644 index 0000000000..23447ce5be --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -0,0 +1,222 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { PointerEvent, useEffect, useRef, useState } from 'react'; + +import { clampPointBetweenImage, isPointInShape, pointInRectangle } from '@geti/smart-tools/utils'; + +import { useZoom } from '../../../../components/zoom/zoom'; +import { AnnotationShape } from '../../annotations/annotation-shape.component'; +import { MaskAnnotations } from '../../annotations/mask-annotations.component'; +import { Annotation, Point, RegionOfInterest, Shape } from '../../types'; +import { isRightButton } from '../../utils'; +import { getRelativePoint, removeOffLimitPoints } from '../utils'; +import { InteractiveSegmentationPoint } from './interactive-segmentation-point.component'; +import { useSegmentAnything } from './segment-anything-state-provider.component'; +import { InteractiveAnnotationPoint } from './segment-anything.interface'; +import { useSingleStackFn } from './use-single-stack-fn.hook'; +import { useThrottledCallback } from './use-throttle-callback.hook'; + +import classes from './segment-anything.module.scss'; + +const isPositivePoint = (point: Point, shapes: Shape[], isRightClick: boolean, rightClickMode: boolean) => { + if (rightClickMode) { + return !isRightClick; + } + + return !shapes.some((shape) => isPointInShape(shape, point)); +}; + +// Whenever the user moves their mouse over the canvas we compute a preview of +// SAM being applied to the user's mouse position. +// The decoding step of SAM takes on average 100ms with 150-250ms being a high +// exception. We throttle the mouse update based on this so that we don't overload +// the user's cpu with too many decoding requests +const THROTTLE_TIME = 150; + +const selectedMediaItem = { + identifier: 'id', + image: new ImageData(100, 100), +}; + +const roi: RegionOfInterest = { + x: 0, + y: 0, + width: 100, + height: 100, +}; + +const toolSettings = { + interactiveMode: false, + rightClickMode: false, +}; + +const SELECT_ANNOTATION_STYLES = { + fillOpacity: 0.3, + fill: 'var(--energy-blue-shade)', + stroke: 'var(--energy-blue-shade)', + strokeWidth: 'calc(2px / var(--zoom-level))', +}; + +export const SegmentAnythingTool = () => { + const zoom = useZoom(); + + const clampPoint = clampPointBetweenImage(selectedMediaItem.image); + + const ref = useRef(null); + + const { result, points, addPoint } = useSegmentAnything(); + const [mousePosition, setMousePosition] = useState(); + + const [previewShapes, setPreviewShapes] = useState([]); + const { decodingQueryFn } = useSegmentAnything(); + const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); + + const throttleSetMousePosition = useThrottledCallback((point: InteractiveAnnotationPoint) => { + setMousePosition(point); + }, THROTTLE_TIME); + + useEffect(() => { + if (mousePosition === undefined) { + return; + } + + throttledDecodingQueryFn([mousePosition]) + .then((shapes) => { + setPreviewShapes(shapes.map((shape) => removeOffLimitPoints(shape, roi))); + + throttleSetMousePosition.flush(); + }) + .catch(() => { + // If getting decoding went wrong we set an empty preview and + // start to compute the next decoding + return []; + }); + }, [mousePosition, throttledDecodingQueryFn, throttleSetMousePosition]); + + const { interactiveMode, rightClickMode } = toolSettings; + + const handleMouseMove = (event: PointerEvent) => { + if (!ref.current) { + return; + } + + const point = clampPoint(getRelativePoint(ref.current, { x: event.clientX, y: event.clientY }, zoom.scale)); + + // In task chain don't allow the user to place a point outside the ROI + if (!pointInRectangle(roi, point)) { + return; + } + + const positive = isPositivePoint(point, result.shapes, isRightButton(event), rightClickMode); + + throttleSetMousePosition({ ...point, positive }); + }; + + const onPointerUp = (event: PointerEvent) => { + if (!ref.current) { + return; + } + + if (event.button !== 0 && event.button !== 2) { + return; + } + + if (event.pointerType === 'touch') { + return; + } + + if (!rightClickMode && isRightButton(event)) { + return; + } + + // The user must first place a positive point as otherwise we can't show a preview + if (rightClickMode && isRightButton(event) && points.length === 0) { + return; + } + + const point = clampPoint(getRelativePoint(ref.current, { x: event.clientX, y: event.clientY }, zoom.scale)); + + // In task chain don't allow the user to place a point outside the ROI + if (!pointInRectangle(roi, point)) { + return; + } + + const positive = isPositivePoint(point, result.shapes, isRightButton(event), rightClickMode); + + const shouldKeepPreviousPoints = interactiveMode === true || isRightButton(event); + + addPoint({ x: point.x, y: point.y, positive }, shouldKeepPreviousPoints); + }; + + const showPreviewShapes = result.shapes.length === 0 && mousePosition !== undefined; + const annotations = (showPreviewShapes ? previewShapes : result.shapes).map((shape, idx): Annotation => { + return { + shape, + labels: [{ id: `sam-${idx}`, name: 'SAM', color: 'var(--energy-blue-shade)', isPrediction: true }], + id: `${idx}`, + }; + }); + + return ( + { + throttleSetMousePosition.cancel(); + setMousePosition(undefined); + setPreviewShapes([]); + }} + style={{ + cursor: interactiveMode + ? `url("/icons/pencil-plus.svg") 16 16, auto` + : `url("/icons/selection.svg") 8 8, auto`, + }} + > + + {annotations.map((annotation, idx) => { + return ( + + + + ); + })} + + + {points.map((point, index) => ( + + ))} + + ); +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts new file mode 100644 index 0000000000..db9c682939 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts @@ -0,0 +1,8 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +export interface InteractiveAnnotationPoint { + x: number; + y: number; + positive: boolean; +} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.module.scss b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.module.scss new file mode 100644 index 0000000000..b409528f6e --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.module.scss @@ -0,0 +1,24 @@ +.stroke { + stroke-dasharray: 10; + stroke-dashoffset: 10; +} + +.animateStroke { + stroke-dasharray: 10; + stroke-dashoffset: 10; + animation: dash 40s linear infinite; +} + +@keyframes dash { + to { + stroke-dashoffset: 1000; + } +} + +.layer { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts new file mode 100644 index 0000000000..c5921dc651 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts @@ -0,0 +1,77 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { queryOptions, useMutation, useQuery } from '@tanstack/react-query'; + +import { RegionOfInterest, Shape } from '../../types'; +import { removeOffLimitPoints } from '../utils'; +import { InteractiveAnnotationPoint } from './segment-anything.interface'; + +const selectedMediaItem = { + identifier: 'id', +}; + +const roi: RegionOfInterest = { + x: 0, + y: 0, + width: 100, + height: 100, +}; + +export const useDecodingQueryOptions = ( + points: InteractiveAnnotationPoint[], + queryFn: (points: InteractiveAnnotationPoint[]) => Promise +) => { + // Round points so that when the user slightly moves their mouse we do not + // immediately recompute the decoding + const roundedPoints = points.map((point) => ({ + x: Math.round(point.x), + y: Math.round(point.y), + positive: point.positive, + })); + + return queryOptions({ + queryKey: ['segment-anything-model', 'decoding', selectedMediaItem?.identifier, roundedPoints, roi], + queryFn: async () => { + const shapes = await queryFn(roundedPoints); + + return shapes.map((shape) => { + return removeOffLimitPoints(shape, roi); + }); + }, + staleTime: Infinity, + retry: 0, + }); +}; + +export const useDecodingQuery = ( + points: InteractiveAnnotationPoint[], + queryFn: (points: InteractiveAnnotationPoint[]) => Promise +) => { + const decodingQueryOptions = useDecodingQueryOptions(points, queryFn); + + return useQuery(decodingQueryOptions); +}; + +export const useDecodingMutation = (queryFn: (points: InteractiveAnnotationPoint[]) => Promise) => { + return useMutation({ + mutationFn: async (points: InteractiveAnnotationPoint[]) => { + // Round points so that when the user slightly moves their mouse we do not + // immediately recompute the decoding + const roundedPoints = points.map((point) => ({ + x: Math.round(point.x), + y: Math.round(point.y), + positive: point.positive, + })); + + // TODO: Add callback to add shapes + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const shapes = (await queryFn(roundedPoints)).map((shape) => { + return removeOffLimitPoints(shape, roi); + }); + + // Add the shapes to the canvas here + // addShapes(shapes); + }, + }); +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts new file mode 100644 index 0000000000..d168fbdbc3 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts @@ -0,0 +1,115 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { useEffect, useState } from 'react'; + +import { EncodingOutput, SegmentAnythingModel } from '@geti/smart-tools/segment-anything'; +import { useQuery } from '@tanstack/react-query'; +import { Remote } from 'comlink'; + +import { useSegmentAnythingWorkerQuery } from '../../hooks/use-segment-anything.hook'; +import { convertToolShapeToGetiShape } from '../utils'; +import { InteractiveAnnotationPoint } from './segment-anything.interface'; + +const selectedMediaItem = { + identifier: 'id', + image: new ImageData(100, 100), +}; + +const useDecodingFn = (model: Remote | undefined, encoding: EncodingOutput | undefined) => { + const shapeType = 'polygon'; + + // TODO: look into returning a new "decoder model" instance that already has the encoding data + // stored in memory, to reduce memory usage + return async (points: InteractiveAnnotationPoint[]) => { + if (points.length === 0) { + return []; + } + + if (model === undefined) { + return []; + } + + if (encoding === undefined) { + return []; + } + + const { shapes } = await model.processDecoder(encoding, { + points, + boxes: [], + ouputConfig: { + type: shapeType, + }, + image: undefined, + }); + + return shapes.map(convertToolShapeToGetiShape); + }; +}; + +const useEncodingQuery = (model: Remote | undefined, mediaItem: unknown) => { + return useQuery({ + queryKey: ['segment-anything-model', 'encoding', selectedMediaItem?.identifier], + queryFn: async () => { + if (model === undefined) { + throw new Error('Model not yet initialized'); + } + + if (mediaItem === undefined) { + throw new Error('Media item not selected'); + } + + return await model.processEncoder(selectedMediaItem.image); + }, + staleTime: Infinity, + gcTime: 3600 * 15, + enabled: model !== undefined && mediaItem !== undefined, + }); +}; + +const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'SEGMENT_ANYTHING_ENCODER') => { + const worker = useSegmentAnythingWorkerQuery(algorithmType); + + const [model, setModel] = useState | undefined>(undefined); + const [modelIsLoading, setModelIsLoading] = useState(false); + + useEffect(() => { + const loadWorker = async () => { + setModelIsLoading(true); + + if (worker) { + console.log(worker); + const modelInstance = worker.data; + + console.log('modelInstance: ', modelInstance); + if (modelInstance) { + await modelInstance.init(algorithmType); + + setModel(modelInstance); + } + } + + setModelIsLoading(false); + }; + + if (worker && model === undefined && !modelIsLoading) { + console.log('loading worker'); + loadWorker(); + } + }, [worker, modelIsLoading, algorithmType, model]); + + return model; +}; + +export const useSegmentAnythingModel = () => { + const encoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_ENCODER'); + const decoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_DECODER'); + const isLoading = encoderModel === undefined || decoderModel === undefined; + + const encodingQuery = useEncodingQuery(encoderModel, selectedMediaItem); + const decodingQueryFn = useDecodingFn(decoderModel, encodingQuery.data); + + useEncodingQuery(encoderModel, encodingQuery.isFetching ? undefined : selectedMediaItem); + + return { isLoading, encodingQuery, decodingQueryFn }; +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-single-stack-fn.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-single-stack-fn.hook.ts new file mode 100644 index 0000000000..bcd312c35c --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-single-stack-fn.hook.ts @@ -0,0 +1,65 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { useCallback, useRef } from 'react'; + +export const useSingleStackFn = < + Callback extends (...args: Parameters) => Promise>>, +>( + fn: Callback +) => { + const resolveRef = useRef<() => void>(undefined); + const rejectRef = useRef<() => void>(undefined); + const isProcessing = useRef(false); + + const wrappedFn = useCallback( + async (...args: Parameters): Promise>> => { + // Wait for the previous function call to be finished + await new Promise(async (resolve, reject) => { + // Continue on if we are not waiting for the result of a previous invokation + if (!isProcessing.current) { + return resolve(); + } + + // If the function was invoked while waiting for the previous result then + // we reject the previous invocation + if (rejectRef.current) { + rejectRef.current(); + rejectRef.current = undefined; + resolveRef.current = undefined; + } + + // Let the previous invocation resolve this call, or let any subsequent calls + // cancel this call + rejectRef.current = reject; + resolveRef.current = resolve; + }); + + try { + isProcessing.current = true; + const result = await fn(...args); + return result; + } catch (error) { + // Reject subsequent invocations as something unexpected made the current invocation fail + if (rejectRef.current) { + rejectRef.current(); + rejectRef.current = undefined; + resolveRef.current = undefined; + } + throw error; + } finally { + isProcessing.current = false; + + // Resolve any subsequent invocations that were waiting for this function to complete + if (resolveRef.current) { + resolveRef.current(); + rejectRef.current = undefined; + resolveRef.current = undefined; + } + } + }, + [fn] + ); + + return wrappedFn; +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-throttle-callback.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-throttle-callback.hook.ts new file mode 100644 index 0000000000..418d62b7a6 --- /dev/null +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-throttle-callback.hook.ts @@ -0,0 +1,26 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { useEffect, useMemo } from 'react'; + +import { throttle, type DebouncedFunc } from 'lodash-es'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type Callback = (...args: any[]) => void; + +export const useThrottledCallback = (callback: Callback, delay: number): DebouncedFunc => { + const debouncedCallback = useMemo(() => { + return throttle(callback, delay, { + leading: true, + trailing: true, + }); + }, [callback, delay]); + + useEffect(() => { + return () => { + debouncedCallback.cancel(); + }; + }, [debouncedCallback]); + + return debouncedCallback; +}; From 1f707e3a46c190b59714b4fec9350fb32710ffcc Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Thu, 18 Sep 2025 10:09:46 +0200 Subject: [PATCH 04/29] Replace mocked media item --- ...ment-anything-state-provider.component.tsx | 6 ++++-- .../segment-anything-tool.component.tsx | 16 ++++---------- .../use-decoding-query.hook.ts | 8 +++---- .../use-segment-anything-model.hook.ts | 21 +++++++------------ 4 files changed, 19 insertions(+), 32 deletions(-) diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx index 7b7fd4f3b7..a0739e869d 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -8,6 +8,7 @@ import { toast } from '@geti/ui'; import { useQueryClient, UseQueryResult } from '@tanstack/react-query'; import { isEmpty } from 'lodash-es'; +import { useAnnotator } from '../../annotator-provider.component'; import { Shape } from '../../types'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; import { useDecodingMutation, useDecodingQuery, useDecodingQueryOptions } from './use-decoding-query.hook'; @@ -40,6 +41,8 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode }); const [_, setIsDrawing] = useState(false); + const { addAnnotation } = useAnnotator(); + const queryClient = useQueryClient(); const { encodingQuery, decodingQueryFn, isLoading } = useSegmentAnythingModel(); const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); @@ -81,8 +84,7 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode } if (hasResults) { - // TODO: Add callback to add the shapes to the canvas - // addShapes(outputShapes); + outputShapes.map((shape) => addAnnotation(shape)); } reset(); diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 23447ce5be..76ad4541c5 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -8,6 +8,7 @@ import { clampPointBetweenImage, isPointInShape, pointInRectangle } from '@geti/ import { useZoom } from '../../../../components/zoom/zoom'; import { AnnotationShape } from '../../annotations/annotation-shape.component'; import { MaskAnnotations } from '../../annotations/mask-annotations.component'; +import { useAnnotator } from '../../annotator-provider.component'; import { Annotation, Point, RegionOfInterest, Shape } from '../../types'; import { isRightButton } from '../../utils'; import { getRelativePoint, removeOffLimitPoints } from '../utils'; @@ -34,11 +35,6 @@ const isPositivePoint = (point: Point, shapes: Shape[], isRightClick: boolean, r // the user's cpu with too many decoding requests const THROTTLE_TIME = 150; -const selectedMediaItem = { - identifier: 'id', - image: new ImageData(100, 100), -}; - const roi: RegionOfInterest = { x: 0, y: 0, @@ -60,8 +56,9 @@ const SELECT_ANNOTATION_STYLES = { export const SegmentAnythingTool = () => { const zoom = useZoom(); + const { mediaItem } = useAnnotator(); - const clampPoint = clampPointBetweenImage(selectedMediaItem.image); + const clampPoint = clampPointBetweenImage(new ImageData(mediaItem.width, mediaItem.height)); const ref = useRef(null); @@ -173,12 +170,7 @@ export const SegmentAnythingTool = () => { : `url("/icons/selection.svg") 8 8, auto`, }} > - + {annotations.map((annotation, idx) => { return ( Promise ) => { + const { mediaItem } = useAnnotator(); // Round points so that when the user slightly moves their mouse we do not // immediately recompute the decoding const roundedPoints = points.map((point) => ({ @@ -31,7 +29,7 @@ export const useDecodingQueryOptions = ( })); return queryOptions({ - queryKey: ['segment-anything-model', 'decoding', selectedMediaItem?.identifier, roundedPoints, roi], + queryKey: ['segment-anything-model', 'decoding', mediaItem?.id, roundedPoints, roi], queryFn: async () => { const shapes = await queryFn(roundedPoints); diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts index d168fbdbc3..d9f1c36af5 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts @@ -7,15 +7,12 @@ import { EncodingOutput, SegmentAnythingModel } from '@geti/smart-tools/segment- import { useQuery } from '@tanstack/react-query'; import { Remote } from 'comlink'; +import { useAnnotator } from '../../annotator-provider.component'; import { useSegmentAnythingWorkerQuery } from '../../hooks/use-segment-anything.hook'; +import { MediaItem } from '../../types'; import { convertToolShapeToGetiShape } from '../utils'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; -const selectedMediaItem = { - identifier: 'id', - image: new ImageData(100, 100), -}; - const useDecodingFn = (model: Remote | undefined, encoding: EncodingOutput | undefined) => { const shapeType = 'polygon'; @@ -47,9 +44,9 @@ const useDecodingFn = (model: Remote | undefined, encoding }; }; -const useEncodingQuery = (model: Remote | undefined, mediaItem: unknown) => { +const useEncodingQuery = (model: Remote | undefined, mediaItem: MediaItem | undefined) => { return useQuery({ - queryKey: ['segment-anything-model', 'encoding', selectedMediaItem?.identifier], + queryKey: ['segment-anything-model', 'encoding', mediaItem?.id], queryFn: async () => { if (model === undefined) { throw new Error('Model not yet initialized'); @@ -59,7 +56,7 @@ const useEncodingQuery = (model: Remote | undefined, media throw new Error('Media item not selected'); } - return await model.processEncoder(selectedMediaItem.image); + return await model.processEncoder(new ImageData(mediaItem.width, mediaItem.height)); }, staleTime: Infinity, gcTime: 3600 * 15, @@ -78,10 +75,8 @@ const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'S setModelIsLoading(true); if (worker) { - console.log(worker); const modelInstance = worker.data; - console.log('modelInstance: ', modelInstance); if (modelInstance) { await modelInstance.init(algorithmType); @@ -93,7 +88,6 @@ const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'S }; if (worker && model === undefined && !modelIsLoading) { - console.log('loading worker'); loadWorker(); } }, [worker, modelIsLoading, algorithmType, model]); @@ -104,12 +98,13 @@ const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'S export const useSegmentAnythingModel = () => { const encoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_ENCODER'); const decoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_DECODER'); + const { mediaItem } = useAnnotator(); const isLoading = encoderModel === undefined || decoderModel === undefined; - const encodingQuery = useEncodingQuery(encoderModel, selectedMediaItem); + const encodingQuery = useEncodingQuery(encoderModel, mediaItem); const decodingQueryFn = useDecodingFn(decoderModel, encodingQuery.data); - useEncodingQuery(encoderModel, encodingQuery.isFetching ? undefined : selectedMediaItem); + useEncodingQuery(encoderModel, encodingQuery.isFetching ? undefined : mediaItem); return { isLoading, encodingQuery, decodingQueryFn }; }; From 5e61d5fe5a9ad740cea398a917190d4a774ba4a6 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Thu, 18 Sep 2025 11:35:53 +0200 Subject: [PATCH 05/29] Add missing headers for webworker support --- ui/rsbuild.config.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ui/rsbuild.config.ts b/ui/rsbuild.config.ts index b4db27faa5..fb45a56769 100644 --- a/ui/rsbuild.config.ts +++ b/ui/rsbuild.config.ts @@ -29,7 +29,6 @@ export default defineConfig({ }, }), ], - source: { define: { ...publicVars, @@ -54,4 +53,16 @@ export default defineConfig({ }, }, }, + server: { + headers: { + 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Content-Security-Policy': + "default-src 'self'; " + + "script-src 'self' 'unsafe-eval' blob:; " + + "worker-src 'self' blob:; " + + "connect-src 'self' http://localhost:7860 data:; " + + "style-src 'self' 'unsafe-inline';", + }, + }, }); From a60540c4afd18512016fd05a3edf393e58a0dc40 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 09:55:53 +0200 Subject: [PATCH 06/29] Update lock after rebase --- ui/package-lock.json | 990 ++++++++++++++++++++++++------------------- 1 file changed, 552 insertions(+), 438 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 0d7967d2bc..942ea91bb6 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -2291,6 +2291,33 @@ "statuses": "^2.0.1" } }, + "node_modules/@bundled-es-modules/tough-cookie": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", + "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, + "node_modules/@bundled-es-modules/tough-cookie/node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@csstools/color-helpers": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", @@ -2411,6 +2438,7 @@ "resolved": "https://registry.npmjs.org/@doodle3d/clipper-js/-/clipper-js-1.0.11.tgz", "integrity": "sha512-KSVF9iOl9jGu02EGUnVS2ric4iQRSIypg3/CTM30+MuWsqkUhILIG2EPxvPASENi6483QmNIwGSogZuTE7CFQA==", "license": "MIT", + "peer": true, "dependencies": { "@doodle3d/clipper-lib": "^6.4.2-b" } @@ -2419,7 +2447,8 @@ "version": "6.4.2-b", "resolved": "https://registry.npmjs.org/@doodle3d/clipper-lib/-/clipper-lib-6.4.2-b.tgz", "integrity": "sha512-glELSijsD9b+/0d9iOdasBwqH3s+xPxD59tJ7aXkBx7klugygGOMXn7PB05AdhVyA1OYMj7GUCegaQa7nvLtmQ==", - "license": "BSL" + "license": "BSL", + "peer": true }, "node_modules/@emnapi/core": { "version": "1.5.0", @@ -3041,16 +3070,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3065,9 +3084,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz", - "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==", + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", + "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", "dev": true, "license": "MIT", "engines": { @@ -3231,9 +3250,9 @@ } }, "node_modules/@ianvs/prettier-plugin-sort-imports": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.7.0.tgz", - "integrity": "sha512-soa2bPUJAFruLL4z/CnMfSEKGznm5ebz29fIa9PxYtu8HHyLKNE1NXAs6dylfw1jn/ilEIfO2oLLN6uAafb7DA==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ianvs/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.4.2.tgz", + "integrity": "sha512-KkVFy3TLh0OFzimbZglMmORi+vL/i2OFhEs5M07R9w0IwWAGpsNNyE4CY/2u0YoMF5bawKC2+8/fUH60nnNtjw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3244,24 +3263,12 @@ "semver": "^7.5.2" }, "peerDependencies": { - "@prettier/plugin-oxc": "^0.0.4", "@vue/compiler-sfc": "2.7.x || 3.x", - "content-tag": "^4.0.0", - "prettier": "2 || 3 || ^4.0.0-0", - "prettier-plugin-ember-template-tag": "^2.1.0" + "prettier": "2 || 3 || ^4.0.0-0" }, "peerDependenciesMeta": { - "@prettier/plugin-oxc": { - "optional": true - }, "@vue/compiler-sfc": { "optional": true - }, - "content-tag": { - "optional": true - }, - "prettier-plugin-ember-template-tag": { - "optional": true } } }, @@ -3500,62 +3507,62 @@ } }, "node_modules/@module-federation/error-codes": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.18.0.tgz", - "integrity": "sha512-Woonm8ehyVIUPXChmbu80Zj6uJkC0dD9SJUZ/wOPtO8iiz/m+dkrOugAuKgoiR6qH4F+yorWila954tBz4uKsQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.14.0.tgz", + "integrity": "sha512-GGk+EoeSACJikZZyShnLshtq9E2eCrDWbRiB4QAFXCX4oYmGgFfzXlx59vMNwqTKPJWxkEGnPYacJMcr2YYjag==", "dev": true, "license": "MIT" }, "node_modules/@module-federation/runtime": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.18.0.tgz", - "integrity": "sha512-+C4YtoSztM7nHwNyZl6dQKGUVJdsPrUdaf3HIKReg/GQbrt9uvOlUWo2NXMZ8vDAnf/QRrpSYAwXHmWDn9Obaw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.14.0.tgz", + "integrity": "sha512-kR3cyHw/Y64SEa7mh4CHXOEQYY32LKLK75kJOmBroLNLO7/W01hMNAvGBYTedS7hWpVuefPk1aFZioy3q2VLdQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "0.18.0", - "@module-federation/runtime-core": "0.18.0", - "@module-federation/sdk": "0.18.0" + "@module-federation/error-codes": "0.14.0", + "@module-federation/runtime-core": "0.14.0", + "@module-federation/sdk": "0.14.0" } }, "node_modules/@module-federation/runtime-core": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.18.0.tgz", - "integrity": "sha512-ZyYhrDyVAhUzriOsVfgL6vwd+5ebYm595Y13KeMf6TKDRoUHBMTLGQ8WM4TDj8JNsy7LigncK8C03fn97of0QQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.14.0.tgz", + "integrity": "sha512-fGE1Ro55zIFDp/CxQuRhKQ1pJvG7P0qvRm2N+4i8z++2bgDjcxnCKUqDJ8lLD+JfJQvUJf0tuSsJPgevzueD4g==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "0.18.0", - "@module-federation/sdk": "0.18.0" + "@module-federation/error-codes": "0.14.0", + "@module-federation/sdk": "0.14.0" } }, "node_modules/@module-federation/runtime-tools": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.18.0.tgz", - "integrity": "sha512-fSga9o4t1UfXNV/Kh6qFvRyZpPp3EHSPRISNeyT8ZoTpzDNiYzhtw0BPUSSD8m6C6XQh2s/11rI4g80UY+d+hA==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.14.0.tgz", + "integrity": "sha512-y/YN0c2DKsLETE+4EEbmYWjqF9G6ZwgZoDIPkaQ9p0pQu0V4YxzWfQagFFxR0RigYGuhJKmSU/rtNoHq+qF8jg==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "0.18.0", - "@module-federation/webpack-bundler-runtime": "0.18.0" + "@module-federation/runtime": "0.14.0", + "@module-federation/webpack-bundler-runtime": "0.14.0" } }, "node_modules/@module-federation/sdk": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.18.0.tgz", - "integrity": "sha512-Lo/Feq73tO2unjmpRfyyoUkTVoejhItXOk/h5C+4cistnHbTV8XHrW/13fD5e1Iu60heVdAhhelJd6F898Ve9A==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.14.0.tgz", + "integrity": "sha512-lg/OWRsh18hsyTCamOOhEX546vbDiA2O4OggTxxH2wTGr156N6DdELGQlYIKfRdU/0StgtQS81Goc0BgDZlx9A==", "dev": true, "license": "MIT" }, "node_modules/@module-federation/webpack-bundler-runtime": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.18.0.tgz", - "integrity": "sha512-TEvErbF+YQ+6IFimhUYKK3a5wapD90d90sLsNpcu2kB3QGT7t4nIluE25duXuZDVUKLz86tEPrza/oaaCWTpvQ==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.14.0.tgz", + "integrity": "sha512-POWS6cKBicAAQ3DNY5X7XEUSfOfUsRaBNxbuwEfSGlrkTE9UcWheO06QP2ndHi8tHQuUKcIHi2navhPkJ+k5xg==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "0.18.0", - "@module-federation/sdk": "0.18.0" + "@module-federation/runtime": "0.14.0", + "@module-federation/sdk": "0.14.0" } }, "node_modules/@msw/playwright": { @@ -3616,19 +3623,6 @@ "msw": "^2.10.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.5.tgz", - "integrity": "sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", - "@tybys/wasm-util": "^0.10.1" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4014,13 +4008,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.0.tgz", - "integrity": "sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==", + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.2.tgz", + "integrity": "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.55.0" + "playwright": "1.54.2" }, "bin": { "playwright": "cli.js" @@ -4033,31 +4027,36 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -4067,31 +4066,36 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@react-aria/actiongroup": { "version": "3.7.20", @@ -4114,9 +4118,9 @@ } }, "node_modules/@react-aria/autocomplete": { - "version": "3.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@react-aria/autocomplete/-/autocomplete-3.0.0-rc.2.tgz", - "integrity": "sha512-55KVj5FePFTHk8nWfUUNN8m7rBL+aSRE0CxHI2t8JG3uam3nY7jyuAJy34RBuDEdTsVlMO9Fri/1JragePC2dg==", + "version": "3.0.0-beta.5", + "resolved": "https://registry.npmjs.org/@react-aria/autocomplete/-/autocomplete-3.0.0-beta.5.tgz", + "integrity": "sha512-zYiVeKGYHStpBXS0mf51k14xkVunU/dFqxumfYXDiiyknxIDE4L1kN7XKo16nus3TkTmJtqBHJrWmzCfNkRd9g==", "license": "Apache-2.0", "dependencies": { "@react-aria/combobox": "^3.12.5", @@ -8477,23 +8481,23 @@ ] }, "node_modules/@rsbuild/core": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.5.8.tgz", - "integrity": "sha512-neCNfVxOoE7DsqDB5m1hEwxCwaTRdF6g5Nxq21FaDpSg0TpAdwzYlhHDhaCcriTOP0WhdYBn4l0TRRLP3bPDQQ==", + "version": "1.3.22", + "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.3.22.tgz", + "integrity": "sha512-FGB7m8Tn/uiOhvqk0lw+NRMyD+VYJ+eBqVfpn0X11spkJDiPWn8UkMRvfzCX4XFcNZwRKYuuKJaZK1DNU8UG+w==", "dev": true, "license": "MIT", "dependencies": { - "@rspack/core": "1.5.5", + "@rspack/core": "1.3.12", "@rspack/lite-tapable": "~1.0.1", "@swc/helpers": "^0.5.17", - "core-js": "~3.45.1", - "jiti": "^2.5.1" + "core-js": "~3.42.0", + "jiti": "^2.4.2" }, "bin": { "rsbuild": "bin/rsbuild.js" }, "engines": { - "node": ">=18.12.0" + "node": ">=16.10.0" } }, "node_modules/@rsbuild/plugin-babel": { @@ -8517,13 +8521,13 @@ } }, "node_modules/@rsbuild/plugin-react": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-1.4.0.tgz", - "integrity": "sha512-YhhOUOonJBjnKpUf7E4iXKidldPWAGmYBRtDjQgcSmW4tbW0DasFpNCqLn5870Q2Ly6oCU06sLv+8G597I36+w==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@rsbuild/plugin-react/-/plugin-react-1.3.5.tgz", + "integrity": "sha512-L/GoHgJV4j+EQbI4KOhe5EscM0OHgnSat1eR0Nt5P3JZxpJV2ryO5Yfx5jElPWOkYZZCuk+EWhHWDQ4CkeC5BQ==", "dev": true, "license": "MIT", "dependencies": { - "@rspack/plugin-react-refresh": "^1.5.0", + "@rspack/plugin-react-refresh": "~1.4.3", "react-refresh": "^0.17.0" }, "peerDependencies": { @@ -8531,9 +8535,9 @@ } }, "node_modules/@rsbuild/plugin-sass": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rsbuild/plugin-sass/-/plugin-sass-1.4.0.tgz", - "integrity": "sha512-2XcrXUwJftWsWURsvGKKXc7A4yEAUdVkw+K95Qrfmy5E5IfARik0Ko3TFB1828wdvhZ1OFLvDQEzONCIyQV1yg==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@rsbuild/plugin-sass/-/plugin-sass-1.3.5.tgz", + "integrity": "sha512-nW60+iLmV6fkCaE25xpnppISNveAw9z9xySFFcaU2VcpKQ1bGfGns785jlYRGS10E684zG6tL+NIOBS01uPwhQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8576,28 +8580,27 @@ } }, "node_modules/@rspack/binding": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.5.tgz", - "integrity": "sha512-JkB943uBU0lABnKG/jdO+gg3/eeO9CEQMR/1dL6jSU9GTxaNf3XIVc05RhRC7qoVsiXuhSMMFxWyV0hyHxp2bA==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.3.12.tgz", + "integrity": "sha512-4Ic8lV0+LCBfTlH5aIOujIRWZOtgmG223zC4L3o8WY/+ESAgpdnK6lSSMfcYgRanYLAy3HOmFIp20jwskMpbAg==", "dev": true, "license": "MIT", "optionalDependencies": { - "@rspack/binding-darwin-arm64": "1.5.5", - "@rspack/binding-darwin-x64": "1.5.5", - "@rspack/binding-linux-arm64-gnu": "1.5.5", - "@rspack/binding-linux-arm64-musl": "1.5.5", - "@rspack/binding-linux-x64-gnu": "1.5.5", - "@rspack/binding-linux-x64-musl": "1.5.5", - "@rspack/binding-wasm32-wasi": "1.5.5", - "@rspack/binding-win32-arm64-msvc": "1.5.5", - "@rspack/binding-win32-ia32-msvc": "1.5.5", - "@rspack/binding-win32-x64-msvc": "1.5.5" + "@rspack/binding-darwin-arm64": "1.3.12", + "@rspack/binding-darwin-x64": "1.3.12", + "@rspack/binding-linux-arm64-gnu": "1.3.12", + "@rspack/binding-linux-arm64-musl": "1.3.12", + "@rspack/binding-linux-x64-gnu": "1.3.12", + "@rspack/binding-linux-x64-musl": "1.3.12", + "@rspack/binding-win32-arm64-msvc": "1.3.12", + "@rspack/binding-win32-ia32-msvc": "1.3.12", + "@rspack/binding-win32-x64-msvc": "1.3.12" } }, "node_modules/@rspack/binding-darwin-arm64": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.5.tgz", - "integrity": "sha512-Kg3ywEZHLX+aROfTQ5tMOv+Ud+8b4jk8ruUgsi0W8oBkEkR5xBdhFa9vcf6pzy+gfoLCnEI68U9i8ttm+G0csA==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.3.12.tgz", + "integrity": "sha512-8hKjVTBeWPqkMzFPNWIh72oU9O3vFy3e88wRjMPImDCXBiEYrKqGTTLd/J0SO+efdL3SBD1rX1IvdJpxCv6Yrw==", "cpu": [ "arm64" ], @@ -8609,9 +8612,9 @@ ] }, "node_modules/@rspack/binding-darwin-x64": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.5.5.tgz", - "integrity": "sha512-uoGTYnlYW8m47yiDCKvXOehhAOH12wlePJq4sbUbBoHmG07vbDw7fUqnvy2k8319NTVEpMJWGoKyisgI09/uMQ==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.3.12.tgz", + "integrity": "sha512-Sj4m+mCUxL7oCpdu7OmWT7fpBM7hywk5CM9RDc3D7StaBZbvNtNftafCrTZzTYKuZrKmemTh5SFzT5Tz7tf6GA==", "cpu": [ "x64" ], @@ -8623,9 +8626,9 @@ ] }, "node_modules/@rspack/binding-linux-arm64-gnu": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.5.5.tgz", - "integrity": "sha512-KgVN3TeUJ3iNwwOX3JGY4arvoLHX94eItJ4TeOSyetRiSJUrQI0evP16i5kIh+n+p7mVnXmfUS944Gl+uNsJmg==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.3.12.tgz", + "integrity": "sha512-7MuOxf3/Mhv4mgFdLTvgnt/J+VouNR65DEhorth+RZm3LEWojgoFEphSAMAvpvAOpYSS68Sw4SqsOZi719ia2w==", "cpu": [ "arm64" ], @@ -8637,9 +8640,9 @@ ] }, "node_modules/@rspack/binding-linux-arm64-musl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.5.5.tgz", - "integrity": "sha512-1gKthlCQinXtWar6Hl9Il6BQ/NgYBH0NVuUsjjf85ejD/cTPQENKyIpGvVa1rSIHSfnG/XujUbruHAeY9mEHCA==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.3.12.tgz", + "integrity": "sha512-s6KKj20T9Z1bA8caIjU6EzJbwyDo1URNFgBAlafCT2UC6yX7flstDJJ38CxZacA9A2P24RuQK2/jPSZpWrTUFA==", "cpu": [ "arm64" ], @@ -8651,9 +8654,9 @@ ] }, "node_modules/@rspack/binding-linux-x64-gnu": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.5.5.tgz", - "integrity": "sha512-haPFg4M9GwpSI5g9BQhKUNdzCKDvFexIUkLiAHBjFU9iWQTEcI9VfYPixestOIwzUv7E34rHM+jAsmRGWdgmXw==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.3.12.tgz", + "integrity": "sha512-0w/sRREYbRgHgWvs2uMEJSLfvzbZkPHUg6CMcYQGNVK6axYRot6jPyKetyFYA9pR5fB5rsXegpnFaZaVrRIK2g==", "cpu": [ "x64" ], @@ -8665,9 +8668,9 @@ ] }, "node_modules/@rspack/binding-linux-x64-musl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.5.5.tgz", - "integrity": "sha512-oUny56JEkCZvIu4n8/P7IPLPNtJnL89EDhxHINH87XLBY3OOgo8JHELR11Zj9SFWiGNsRcLqi+Q78tWa0ligBQ==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.3.12.tgz", + "integrity": "sha512-jEdxkPymkRxbijDRsBGdhopcbGXiXDg59lXqIRkVklqbDmZ/O6DHm7gImmlx5q9FoWbz0gqJuOKBz4JqWxjWVA==", "cpu": [ "x64" ], @@ -8678,24 +8681,10 @@ "linux" ] }, - "node_modules/@rspack/binding-wasm32-wasi": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.5.5.tgz", - "integrity": "sha512-tRgxBgIXaBKBH/0KlwvyqbIMqQrg8jKOyFOEQseEE7Oqs2M9KkJ7Vp5QN11u3NvZ9nz5GbZxmVGBMkdj9Gth1w==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.5" - } - }, "node_modules/@rspack/binding-win32-arm64-msvc": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.5.5.tgz", - "integrity": "sha512-wGWd2yluoFdQgtkIbny6FoHnzahTk+o9RzrptjeS1u/NV1lKrWzmWhwZojMGOUqPiaukZKaziOEo7gpRn2XbEQ==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.3.12.tgz", + "integrity": "sha512-ZRvUCb3TDLClAqcTsl/o9UdJf0B5CgzAxgdbnYJbldyuyMeTUB4jp20OfG55M3C2Nute2SNhu2bOOp9Se5Ongw==", "cpu": [ "arm64" ], @@ -8707,9 +8696,9 @@ ] }, "node_modules/@rspack/binding-win32-ia32-msvc": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.5.5.tgz", - "integrity": "sha512-Ikml8AQkzjPCG24vTO4pG2bpJ8vp93jVEgo9X9uYjO2vQbIp5QSOmeZOTM7tXCf8AfTfHEF/yAdE/pR/+tXXGQ==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.3.12.tgz", + "integrity": "sha512-1TKPjuXStPJr14f3ZHuv40Xc/87jUXx10pzVtrPnw+f3hckECHrbYU/fvbVzZyuXbsXtkXpYca6ygCDRJAoNeQ==", "cpu": [ "ia32" ], @@ -8721,9 +8710,9 @@ ] }, "node_modules/@rspack/binding-win32-x64-msvc": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.5.5.tgz", - "integrity": "sha512-m2059ms0i/GIQGWTlZ5GI6SWpuMFAPMsWlhXLk2LZRIydhi+N/YPkmc33lFRTlDA3QpKDCvowvCvIIA7g6WSlg==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.3.12.tgz", + "integrity": "sha512-lCR0JfnYKpV+a6r2A2FdxyUKUS4tajePgpPJN5uXDgMGwrDtRqvx+d0BHhwjFudQVJq9VVbRaL89s2MQ6u+xYw==", "cpu": [ "x64" ], @@ -8735,18 +8724,19 @@ ] }, "node_modules/@rspack/core": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.5.5.tgz", - "integrity": "sha512-AOIuMktK6X/xHAjJ/0QJ2kbSkILXj641GCPE+EOfWO27ODA8fHPArKbyz5AVGVePV3aUfEo2VFcsNzP67VBEPA==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.3.12.tgz", + "integrity": "sha512-mAPmV4LPPRgxpouUrGmAE4kpF1NEWJGyM5coebsjK/zaCMSjw3mkdxiU2b5cO44oIi0Ifv5iGkvwbdrZOvMyFA==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime-tools": "0.18.0", - "@rspack/binding": "1.5.5", - "@rspack/lite-tapable": "1.0.1" + "@module-federation/runtime-tools": "0.14.0", + "@rspack/binding": "1.3.12", + "@rspack/lite-tapable": "1.0.1", + "caniuse-lite": "^1.0.30001718" }, "engines": { - "node": ">=18.12.0" + "node": ">=16.0.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" @@ -8768,9 +8758,9 @@ } }, "node_modules/@rspack/plugin-react-refresh": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.5.1.tgz", - "integrity": "sha512-GT3KV1GSmIXO8dQg6taNf9AuZ8XHEs8cZqRn5mC2GT6DPCvUA/ZKezIGsHTyH+HMEbJnJ/T8yYeJnvnzuUcqAQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.4.3.tgz", + "integrity": "sha512-wZx4vWgy5oMEvgyNGd/oUKcdnKaccYWHCRkOqTdAPJC3WcytxhTX+Kady8ERurSBiLyQpoMiU3Iyd+F1Y2Arbw==", "dev": true, "license": "MIT", "dependencies": { @@ -9151,13 +9141,13 @@ } }, "node_modules/@tanstack/eslint-plugin-query": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.89.0.tgz", - "integrity": "sha512-vz8TEuw9GO0xXIdreMpcofvOY17T3cjgob9bSFln8yQsKsbsUvtpvV3F8pVC3tZEDq0IwO++3/e0/+7YKEarNA==", + "version": "5.78.0", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.78.0.tgz", + "integrity": "sha512-hYkhWr3UP0CkAsn/phBVR98UQawbw8CmTSgWtdgEBUjI60/GBaEIkpgi/Bp/2I8eIDK4+vdY7ac6jZx+GR+hEQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.37.0" + "@typescript-eslint/utils": "^8.18.1" }, "funding": { "type": "github", @@ -9168,9 +9158,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.89.0.tgz", - "integrity": "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==", + "version": "5.80.12", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.80.12.tgz", + "integrity": "sha512-Cy+l+jNuII87oGpzkJ+nGDydzWJeq+gDr72lGURHXjD0UqZh5yRXcLg0Ix7jG+0Tn/ayGnR9+yph7Vbf1j8QZA==", "license": "MIT", "funding": { "type": "github", @@ -9178,12 +9168,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz", - "integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==", + "version": "5.80.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.80.12.tgz", + "integrity": "sha512-hCtE5hw4rSqMcHSlkVLhM6jXy55rQsCE8qmgLq2MIqf/r4dRFrVlSqMczmO5w0ZQMYWeeHCYMrdRxtadajQK/Q==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.89.0" + "@tanstack/query-core": "5.80.12" }, "funding": { "type": "github", @@ -9194,9 +9184,9 @@ } }, "node_modules/@tauri-apps/cli": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.8.4.tgz", - "integrity": "sha512-ejUZBzuQRcjFV+v/gdj/DcbyX/6T4unZQjMSBZwLzP/CymEjKcc2+Fc8xTORThebHDUvqoXMdsCZt8r+hyN15g==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.6.2.tgz", + "integrity": "sha512-s1/eyBHxk0wG1blLeOY2IDjgZcxVrkxU5HFL8rNDwjYGr0o7yr3RAtwmuUPhz13NO+xGAL1bJZaLFBdp+5joKg==", "dev": true, "license": "Apache-2.0 OR MIT", "bin": { @@ -9210,23 +9200,23 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.8.4", - "@tauri-apps/cli-darwin-x64": "2.8.4", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.8.4", - "@tauri-apps/cli-linux-arm64-gnu": "2.8.4", - "@tauri-apps/cli-linux-arm64-musl": "2.8.4", - "@tauri-apps/cli-linux-riscv64-gnu": "2.8.4", - "@tauri-apps/cli-linux-x64-gnu": "2.8.4", - "@tauri-apps/cli-linux-x64-musl": "2.8.4", - "@tauri-apps/cli-win32-arm64-msvc": "2.8.4", - "@tauri-apps/cli-win32-ia32-msvc": "2.8.4", - "@tauri-apps/cli-win32-x64-msvc": "2.8.4" + "@tauri-apps/cli-darwin-arm64": "2.6.2", + "@tauri-apps/cli-darwin-x64": "2.6.2", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.6.2", + "@tauri-apps/cli-linux-arm64-gnu": "2.6.2", + "@tauri-apps/cli-linux-arm64-musl": "2.6.2", + "@tauri-apps/cli-linux-riscv64-gnu": "2.6.2", + "@tauri-apps/cli-linux-x64-gnu": "2.6.2", + "@tauri-apps/cli-linux-x64-musl": "2.6.2", + "@tauri-apps/cli-win32-arm64-msvc": "2.6.2", + "@tauri-apps/cli-win32-ia32-msvc": "2.6.2", + "@tauri-apps/cli-win32-x64-msvc": "2.6.2" } }, "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.8.4.tgz", - "integrity": "sha512-BKu8HRkYV01SMTa7r4fLx+wjgtRK8Vep7lmBdHDioP6b8XH3q2KgsAyPWfEZaZIkZ2LY4SqqGARaE9oilNe0oA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.6.2.tgz", + "integrity": "sha512-YlvT+Yb7u2HplyN2Cf/nBplCQARC/I4uedlYHlgtxg6rV7xbo9BvG1jLOo29IFhqA2rOp5w1LtgvVGwsOf2kxw==", "cpu": [ "arm64" ], @@ -9241,9 +9231,9 @@ } }, "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.8.4.tgz", - "integrity": "sha512-imb9PfSd/7G6VAO7v1bQ2A3ZH4NOCbhGJFLchxzepGcXf9NKkfun157JH9mko29K6sqAwuJ88qtzbKCbWJTH9g==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.6.2.tgz", + "integrity": "sha512-21gdPWfv1bP8rkTdCL44in70QcYcPaDM70L+y78N8TkBuC+/+wqnHcwwjzb+mUyck6UoEw2DORagSI/oKKUGJw==", "cpu": [ "x64" ], @@ -9258,9 +9248,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.8.4.tgz", - "integrity": "sha512-Ml215UnDdl7/fpOrF1CNovym/KjtUbCuPgrcZ4IhqUCnhZdXuphud/JT3E8X97Y03TZ40Sjz8raXYI2ET0exzw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.6.2.tgz", + "integrity": "sha512-MW8Y6HqHS5yzQkwGoLk/ZyE1tWpnz/seDoY4INsbvUZdknuUf80yn3H+s6eGKtT/0Bfqon/W9sY7pEkgHRPQgA==", "cpu": [ "arm" ], @@ -9275,9 +9265,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.8.4.tgz", - "integrity": "sha512-pbcgBpMyI90C83CxE5REZ9ODyIlmmAPkkJXtV398X3SgZEIYy5TACYqlyyv2z5yKgD8F8WH4/2fek7+jH+ZXAw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.6.2.tgz", + "integrity": "sha512-9PdINTUtnyrnQt9hvC4y1m0NoxKSw/wUB9OTBAQabPj8WLAdvySWiUpEiqJjwLhlu4T6ltXZRpNTEzous3/RXg==", "cpu": [ "arm64" ], @@ -9292,9 +9282,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.8.4.tgz", - "integrity": "sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.6.2.tgz", + "integrity": "sha512-LrcJTRr7FrtQlTDkYaRXIGo/8YU/xkWmBPC646WwKNZ/S6yqCiDcOMoPe7Cx4ZvcG6sK6LUCLQMfaSNEL7PT0A==", "cpu": [ "arm64" ], @@ -9309,9 +9299,9 @@ } }, "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.8.4.tgz", - "integrity": "sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.6.2.tgz", + "integrity": "sha512-GnTshO/BaZ9KGIazz2EiFfXGWgLur5/pjqklRA/ck42PGdUQJhV/Ao7A7TdXPjqAzpFxNo6M/Hx0GCH2iMS7IA==", "cpu": [ "riscv64" ], @@ -9326,9 +9316,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.8.4.tgz", - "integrity": "sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.6.2.tgz", + "integrity": "sha512-QDG3WeJD6UJekmrtVPCJRzlKgn9sGzhvD58oAw5gIU+DRovgmmG2U1jH9fS361oYGjWWO7d/KM9t0kugZzi4lQ==", "cpu": [ "x64" ], @@ -9343,9 +9333,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.8.4.tgz", - "integrity": "sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.6.2.tgz", + "integrity": "sha512-TNVTDDtnWzuVqWBFdZ4+8ZTg17tc21v+CT5XBQ+KYCoYtCrIaHpW04fS5Tmudi+vYdBwoPDfwpKEB6LhCeFraQ==", "cpu": [ "x64" ], @@ -9360,9 +9350,9 @@ } }, "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.8.4.tgz", - "integrity": "sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.6.2.tgz", + "integrity": "sha512-z77C1oa/hMLO/jM1JF39tK3M3v9nou7RsBnQoOY54z5WPcpVAbS0XdFhXB7sSN72BOiO3moDky9lQANQz6L3CA==", "cpu": [ "arm64" ], @@ -9377,9 +9367,9 @@ } }, "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.8.4.tgz", - "integrity": "sha512-yj7WDxkL1t9Uzr2gufQ1Hl7hrHuFKTNEOyascbc109EoiAqCp0tgZ2IykQqOZmZOHU884UAWI1pVMqBhS/BfhA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.6.2.tgz", + "integrity": "sha512-TmD8BbzbjluBw8+QEIWUVmFa9aAluSkT1N937n1mpYLXcPbTpbunqRFiIznTwupoJNJIdtpF/t7BdZDRh5rrcg==", "cpu": [ "ia32" ], @@ -9394,9 +9384,9 @@ } }, "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.8.4.tgz", - "integrity": "sha512-XuvGB4ehBdd7QhMZ9qbj/8icGEatDuBNxyYHbLKsTYh90ggUlPa/AtaqcC1Fo69lGkTmq9BOKrs1aWSi7xDonA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.6.2.tgz", + "integrity": "sha512-ItB8RCKk+nCmqOxOvbNtltz6x1A4QX6cSM21kj3NkpcnjT9rHSMcfyf8WVI2fkoMUJR80iqCblUX6ARxC3lj6w==", "cpu": [ "x64" ], @@ -9431,9 +9421,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.8.0.tgz", - "integrity": "sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.4.tgz", + "integrity": "sha512-xDXgLjVunjHqczScfkCJ9iyjdNOVHvvCdqHSSxwM9L0l/wHkTRum67SDc020uAlCoqktJplgO2AAQeLP1wgqDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9441,6 +9431,7 @@ "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", "picocolors": "^1.1.1", "redent": "^3.0.0" }, @@ -9705,12 +9696,12 @@ } }, "node_modules/@types/node": { - "version": "24.5.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.1.tgz", - "integrity": "sha512-/SQdmUP2xa+1rdx7VwB9yPq8PaKej8TD5cQ+XfKDPWWC+VDJU4rvVVagXqKUzhKjtFoNA8rXDJAkCxQPAe00+Q==", + "version": "24.0.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.15.tgz", + "integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==", "license": "MIT", "dependencies": { - "undici-types": "~7.12.0" + "undici-types": "~7.8.0" } }, "node_modules/@types/parse-json": { @@ -9747,6 +9738,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", @@ -9755,17 +9753,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.0.tgz", - "integrity": "sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz", + "integrity": "sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.44.0", - "@typescript-eslint/type-utils": "8.44.0", - "@typescript-eslint/utils": "8.44.0", - "@typescript-eslint/visitor-keys": "8.44.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/type-utils": "8.31.1", + "@typescript-eslint/utils": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -9779,9 +9777,123 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.44.0", + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz", + "integrity": "sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.1.tgz", + "integrity": "sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz", + "integrity": "sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.1.tgz", + "integrity": "sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/typescript-estree": "8.31.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz", + "integrity": "sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.31.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@typescript-eslint/parser": { @@ -9868,15 +9980,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.0.tgz", - "integrity": "sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz", + "integrity": "sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.44.0", - "@typescript-eslint/typescript-estree": "8.44.0", - "@typescript-eslint/utils": "8.44.0", + "@typescript-eslint/typescript-estree": "8.31.1", + "@typescript-eslint/utils": "8.31.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -9889,7 +10000,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { @@ -11490,9 +11601,9 @@ } }, "node_modules/core-js": { - "version": "3.45.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", - "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", + "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -12426,20 +12537,20 @@ } }, "node_modules/eslint": { - "version": "9.35.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", - "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", + "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.13.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.35.0", - "@eslint/plugin-kit": "^0.3.5", + "@eslint/js": "9.25.1", + "@eslint/plugin-kit": "^0.2.8", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -12486,31 +12597,6 @@ } } }, - "node_modules/eslint-import-context": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", - "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-tsconfig": "^4.10.1", - "stable-hash-x": "^0.2.0" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-import-context" - }, - "peerDependencies": { - "unrs-resolver": "^1.0.0" - }, - "peerDependenciesMeta": { - "unrs-resolver": { - "optional": true - } - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -12534,18 +12620,18 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", - "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.3.5.tgz", + "integrity": "sha512-QGwhLrwn/WGOsdrWvjhm9n8BvKN/Wr41SQERMV7DQ2hm9+Ozas39CyQUxum///l2G2vefQVr7VbIaCFS5h9g5g==", "dev": true, "license": "ISC", "dependencies": { "debug": "^4.4.0", "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", - "stable-hash-x": "^0.2.0", - "tinyglobby": "^0.2.14", - "unrs-resolver": "^1.7.11" + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.3" }, "engines": { "node": "^16.17.0 || >=18.6.0" @@ -12973,16 +13059,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -13254,7 +13330,8 @@ "version": "1.12.0", "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==", - "license": "SEE LICENSE IN LICENSE.txt" + "license": "SEE LICENSE IN LICENSE.txt", + "peer": true }, "node_modules/flatted": { "version": "3.3.3", @@ -13553,7 +13630,8 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz", "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/harmony-reflect": { "version": "1.6.2", @@ -13772,9 +13850,9 @@ } }, "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -14675,7 +14753,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/loose-envify": { "version": "1.4.0", @@ -14859,15 +14938,16 @@ "license": "MIT" }, "node_modules/msw": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.2.tgz", - "integrity": "sha512-MI54hLCsrMwiflkcqlgYYNJJddY5/+S0SnONvhv1owOplvqohKSQyGejpNdUGyCwgs4IH7PqaNbPw/sKOEze9Q==", + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.10.5.tgz", + "integrity": "sha512-0EsQCrCI1HbhpBWd89DvmxY6plmvrM96b0sCIztnvcNHQbXn5vqwm1KlXslo6u4wN9LFGLC1WFjjgljcQhe40A==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@bundled-es-modules/cookie": "^2.0.1", "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", "@inquirer/confirm": "^5.0.0", "@mswjs/interceptors": "^0.39.1", "@open-draft/deferred-promise": "^2.2.0", @@ -14880,9 +14960,7 @@ "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", - "rettime": "^0.7.0", "strict-event-emitter": "^0.5.1", - "tough-cookie": "^6.0.0", "type-fest": "^4.26.1", "yargs": "^17.7.2" }, @@ -14904,39 +14982,6 @@ } } }, - "node_modules/msw/node_modules/tldts": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.14.tgz", - "integrity": "sha512-lMNHE4aSI3LlkMUMicTmAG3tkkitjOQGDTFboPJwAg2kJXKP1ryWEyqujktg5qhrFZOkk5YFzgkxg3jErE+i5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^7.0.14" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/msw/node_modules/tldts-core": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.14.tgz", - "integrity": "sha512-viZGNK6+NdluOJWwTO9olaugx0bkKhscIdriQQ+lNNhwitIKvb+SvhbYgnCz6j9p7dX3cJntt4agQAKMXLjJ5g==", - "dev": true, - "license": "MIT" - }, - "node_modules/msw/node_modules/tough-cookie": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^7.0.5" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", @@ -15201,13 +15246,15 @@ "version": "1.16.3", "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.16.3.tgz", "integrity": "sha512-ZZfFzEqBf6YIGwB9PtBLESHI53jMXA+/hn+ACVUbEfPuK2xI5vMGpLPn+idpwCmHsKJNRzRwqV12K+6TQj6tug==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/onnxruntime-web": { "version": "1.16.3", "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.16.3.tgz", "integrity": "sha512-8O1xCG/RcNQNYYWvdiQJSNpncVg78OVOFeV6MYs/jx++/b12oje8gYUzKqz9wR/sXiX/8TCvdyHgEjj5gQGKUg==", "license": "MIT", + "peer": true, "dependencies": { "flatbuffers": "^1.12.0", "guid-typescript": "^1.0.9", @@ -15227,9 +15274,9 @@ } }, "node_modules/openapi-msw": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/openapi-msw/-/openapi-msw-1.3.0.tgz", - "integrity": "sha512-qRe9zEHSYRi9s9EimTF/IxsG6yvEilkg+pn4Y0QldkuIx+13HcjoNACEumVdpc87nR5AtPErbzuuWFv+cw6fhg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/openapi-msw/-/openapi-msw-1.2.0.tgz", + "integrity": "sha512-Ksm8xG8Lm8O9IU0rC7d1rQ0kcqYf5+qW+iz94G5fuZ/tfinjzSPnhBEwRj7dStvlqCMFQEriVWt7rplbvg0zqA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -15257,17 +15304,17 @@ "license": "MIT" }, "node_modules/openapi-typescript": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.9.1.tgz", - "integrity": "sha512-9gJtoY04mk6iPMbToPjPxEAtfXZ0dTsMZtsgUI8YZta0btPPig9DJFP4jlerQD/7QOwYgb0tl+zLUpDf7vb7VA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.8.0.tgz", + "integrity": "sha512-1EeVWmDzi16A+siQlo/SwSGIT7HwaFAVjvMA7/jG5HMLSnrUOzPL7uSTRZZa4v/LCRxHTApHKtNY6glApEoiUQ==", "dev": true, "license": "MIT", "dependencies": { - "@redocly/openapi-core": "^1.34.5", + "@redocly/openapi-core": "^1.34.3", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.3.0", - "supports-color": "^10.1.0", + "supports-color": "^10.0.0", "yargs-parser": "^21.1.1" }, "bin": { @@ -15563,16 +15610,17 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/playwright": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.0.tgz", - "integrity": "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==", + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz", + "integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.55.0" + "playwright-core": "1.54.2" }, "bin": { "playwright": "cli.js" @@ -15585,9 +15633,9 @@ } }, "node_modules/playwright-core": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz", - "integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==", + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz", + "integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -15612,6 +15660,7 @@ "resolved": "https://registry.npmjs.org/polylabel/-/polylabel-1.1.0.tgz", "integrity": "sha512-bxaGcA40sL3d6M4hH72Z4NdLqxpXRsCFk8AITYg6x1rn1Ei3izf00UMLklerBZTO49aPA3CYrIwVulx2Bce2pA==", "license": "ISC", + "peer": true, "dependencies": { "tinyqueue": "^2.0.3" } @@ -15666,9 +15715,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", "bin": { @@ -15732,6 +15781,7 @@ "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", "hasInstallScript": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -15750,6 +15800,19 @@ "node": ">=12.0.0" } }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -15760,6 +15823,13 @@ "node": ">=6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15859,39 +15929,38 @@ } }, "node_modules/react-aria-components": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.12.2.tgz", - "integrity": "sha512-BTA697VWy6Who9cpSbll447kqqpwxYvN6QF3/+AmXO+M+KgUXtPZAaNXu/9Sv2LdshU0zhIea4w27ZOt57UzPQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.10.1.tgz", + "integrity": "sha512-Mllbk2pQax2EwlOJsXG4oTp6P7P33m82/47M9Os+zaGhSCqo2EilFvThxCFxhLa7ncjLV0ka6wFIYLmZiOcWxw==", "license": "Apache-2.0", "dependencies": { "@internationalized/date": "^3.8.2", "@internationalized/string": "^3.2.7", - "@react-aria/autocomplete": "3.0.0-rc.2", - "@react-aria/collections": "3.0.0-rc.7", - "@react-aria/dnd": "^3.11.2", - "@react-aria/focus": "^3.21.1", - "@react-aria/interactions": "^3.25.5", - "@react-aria/live-announcer": "^3.4.4", - "@react-aria/overlays": "^3.29.1", - "@react-aria/ssr": "^3.9.10", - "@react-aria/textfield": "^3.18.1", - "@react-aria/toolbar": "3.0.0-beta.20", - "@react-aria/utils": "^3.30.1", - "@react-aria/virtualizer": "^4.1.9", - "@react-stately/autocomplete": "3.0.0-beta.3", - "@react-stately/layout": "^4.5.0", - "@react-stately/selection": "^3.20.5", - "@react-stately/table": "^3.15.0", - "@react-stately/utils": "^3.10.8", - "@react-stately/virtualizer": "^4.4.3", - "@react-types/form": "^3.7.15", - "@react-types/grid": "^3.3.5", - "@react-types/shared": "^3.32.0", - "@react-types/table": "^3.13.3", + "@react-aria/autocomplete": "3.0.0-beta.5", + "@react-aria/collections": "3.0.0-rc.3", + "@react-aria/dnd": "^3.10.1", + "@react-aria/focus": "^3.20.5", + "@react-aria/interactions": "^3.25.3", + "@react-aria/live-announcer": "^3.4.3", + "@react-aria/overlays": "^3.27.3", + "@react-aria/ssr": "^3.9.9", + "@react-aria/toolbar": "3.0.0-beta.18", + "@react-aria/utils": "^3.29.1", + "@react-aria/virtualizer": "^4.1.7", + "@react-stately/autocomplete": "3.0.0-beta.2", + "@react-stately/layout": "^4.3.1", + "@react-stately/selection": "^3.20.3", + "@react-stately/table": "^3.14.3", + "@react-stately/utils": "^3.10.7", + "@react-stately/virtualizer": "^4.4.1", + "@react-types/form": "^3.7.13", + "@react-types/grid": "^3.3.3", + "@react-types/shared": "^3.30.0", + "@react-types/table": "^3.13.1", "@swc/helpers": "^0.5.0", "client-only": "^0.0.1", - "react-aria": "^3.43.2", - "react-stately": "^3.41.0", + "react-aria": "^3.41.1", + "react-stately": "^3.39.0", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { @@ -15899,6 +15968,41 @@ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, + "node_modules/react-aria-components/node_modules/@react-aria/collections": { + "version": "3.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@react-aria/collections/-/collections-3.0.0-rc.3.tgz", + "integrity": "sha512-TX6aAzK/FMTvT78LNdSSacKYDnfBWyW5WzxfoQiu/K/kbZVrYSrQaXFrGjkwGEhgmU0O1S4mupANMEgmgI3wlQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.25.3", + "@react-aria/ssr": "^3.9.9", + "@react-aria/utils": "^3.29.1", + "@react-types/shared": "^3.30.0", + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-aria-components/node_modules/@react-aria/toolbar": { + "version": "3.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@react-aria/toolbar/-/toolbar-3.0.0-beta.18.tgz", + "integrity": "sha512-P1fXhmTRBK4YvPQDzCY3XoZl+HiBADgvQ89jszxJ2jD4Qzs/E096ttCc+otZnbvRcoU27IxC2vWFInqK/bP31g==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.20.5", + "@react-aria/i18n": "^3.12.10", + "@react-aria/utils": "^3.29.1", + "@react-types/shared": "^3.30.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/react-dom": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", @@ -16253,6 +16357,13 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -16304,13 +16415,6 @@ "node": ">=4" } }, - "node_modules/rettime": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz", - "integrity": "sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==", - "dev": true, - "license": "MIT" - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -17091,10 +17195,10 @@ "node": ">=0.10.0" } }, - "node_modules/stable-hash-x": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", - "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", "dev": true, "license": "MIT" }, @@ -17608,7 +17712,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/tinyrainbow": { "version": "2.0.0", @@ -17839,9 +17944,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -17853,16 +17958,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.44.0.tgz", - "integrity": "sha512-ib7mCkYuIzYonCq9XWF5XNw+fkj2zg629PSa9KNIQ47RXFF763S5BIX4wqz1+FLPogTZoiw8KmCiRPRa8bL3qw==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.31.1.tgz", + "integrity": "sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.44.0", - "@typescript-eslint/parser": "8.44.0", - "@typescript-eslint/typescript-estree": "8.44.0", - "@typescript-eslint/utils": "8.44.0" + "@typescript-eslint/eslint-plugin": "8.31.1", + "@typescript-eslint/parser": "8.31.1", + "@typescript-eslint/utils": "8.31.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -17873,7 +17977,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { @@ -18035,9 +18139,9 @@ } }, "node_modules/undici-types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", - "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -18084,6 +18188,16 @@ "node": ">=4" } }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unrs-resolver": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", @@ -18178,6 +18292,17 @@ "dev": true, "license": "MIT" }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", @@ -18255,18 +18380,18 @@ } }, "node_modules/vite": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", - "integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.7.tgz", + "integrity": "sha512-hc6LujN/EkJHmxeiDJMs0qBontZ1cdBvvoCbWhVjzUFTU329VRyOC46gHNSA8NcOC5yzCeXpwI40tieI3DEZqg==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", - "fdir": "^6.5.0", + "fdir": "^6.4.6", "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "rollup": "^4.40.0", + "tinyglobby": "^0.2.14" }, "bin": { "vite": "bin/vite.js" @@ -18353,13 +18478,13 @@ } }, "node_modules/vite-plugin-svgr": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.5.0.tgz", - "integrity": "sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.3.0.tgz", + "integrity": "sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==", "dev": true, "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.2.0", + "@rollup/pluginutils": "^5.1.3", "@svgr/core": "^8.1.0", "@svgr/plugin-jsx": "^8.1.0" }, @@ -19001,11 +19126,6 @@ "packages/smart-tools": { "name": "@geti/smart-tools", "version": "1.0.0", - "dependencies": { - "@doodle3d/clipper-js": "~1.0.11", - "onnxruntime-web": "~1.16.3", - "polylabel": "~1.1.0" - }, "devDependencies": { "@geti/config": "*", "@types/node": "^22.15.3", @@ -19016,6 +19136,11 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "typescript": "^5.8.3" + }, + "peerDependencies": { + "@doodle3d/clipper-js": "~1.0.11", + "onnxruntime-web": "~1.16.3", + "polylabel": "~1.1.0" } }, "packages/smart-tools/node_modules/@eslint/config-array": { @@ -19093,17 +19218,6 @@ "undici-types": "~6.21.0" } }, - "packages/smart-tools/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "packages/smart-tools/node_modules/eslint": { "version": "9.35.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", From 4c2ca9afc80169b0b622748a5f782f7a19b39db9 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 09:56:10 +0200 Subject: [PATCH 07/29] Consolidate hooks into one file and fix image data --- .../hooks/use-segment-anything.hook.ts | 24 ---- ...ment-anything-state-provider.component.tsx | 2 +- ...l.hook.ts => use-segment-anything.hook.ts} | 128 ++++++++++-------- 3 files changed, 69 insertions(+), 85 deletions(-) delete mode 100644 ui/src/features/annotator/hooks/use-segment-anything.hook.ts rename ui/src/features/annotator/tools/segment-anything-tool/{use-segment-anything-model.hook.ts => use-segment-anything.hook.ts} (62%) diff --git a/ui/src/features/annotator/hooks/use-segment-anything.hook.ts b/ui/src/features/annotator/hooks/use-segment-anything.hook.ts deleted file mode 100644 index 2da5d8bf91..0000000000 --- a/ui/src/features/annotator/hooks/use-segment-anything.hook.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -import { useQuery } from '@tanstack/react-query'; -import { wrap } from 'comlink'; - -export const useSegmentAnythingWorkerQuery = ( - algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'SEGMENT_ANYTHING_ENCODER' -) => { - return useQuery({ - queryKey: ['workers', algorithmType], - queryFn: async () => { - const segmentAnythingWorker = wrap( - new Worker(new URL('../webworkers/segment-anything.worker', import.meta.url), { - type: 'module', - }) - ); - - // @ts-expect-error build exists on every worker - return segmentAnythingWorker.build(); - }, - staleTime: Infinity, - }); -}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx index a0739e869d..c237f62e60 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -12,7 +12,7 @@ import { useAnnotator } from '../../annotator-provider.component'; import { Shape } from '../../types'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; import { useDecodingMutation, useDecodingQuery, useDecodingQueryOptions } from './use-decoding-query.hook'; -import { useSegmentAnythingModel } from './use-segment-anything-model.hook'; +import { useSegmentAnythingModel } from './use-segment-anything.hook'; import { useSingleStackFn } from './use-single-stack-fn.hook'; interface SegmentAnythingState { diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts similarity index 62% rename from ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts rename to ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts index d9f1c36af5..c1aac4938f 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything-model.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts @@ -1,21 +1,82 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { EncodingOutput, SegmentAnythingModel } from '@geti/smart-tools/segment-anything'; import { useQuery } from '@tanstack/react-query'; -import { Remote } from 'comlink'; +import { Remote, wrap } from 'comlink'; import { useAnnotator } from '../../annotator-provider.component'; -import { useSegmentAnythingWorkerQuery } from '../../hooks/use-segment-anything.hook'; import { MediaItem } from '../../types'; import { convertToolShapeToGetiShape } from '../utils'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; -const useDecodingFn = (model: Remote | undefined, encoding: EncodingOutput | undefined) => { - const shapeType = 'polygon'; +const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'SEGMENT_ANYTHING_ENCODER') => { + const { data } = useQuery>({ + queryKey: ['workers', algorithmType], + queryFn: async () => { + const baseWorker = new Worker(new URL('../../webworkers/segment-anything.worker', import.meta.url), { + type: 'module', + }); + const samWorker = wrap(baseWorker); + + // @ts-expect-error build exists on every worker + return samWorker.build(); + }, + staleTime: Infinity, + }); + + const modelRef = useRef>(undefined); + const [modelIsLoading, setModelIsLoading] = useState(false); + + useEffect(() => { + const loadWorker = async () => { + setModelIsLoading(true); + + if (data) { + const model = data; + + await model.init(algorithmType); + + modelRef.current = model; + } + + setModelIsLoading(false); + }; + + if (data && modelRef.current === undefined && !modelIsLoading) { + loadWorker(); + } + }, [data, modelIsLoading, algorithmType]); + + return modelRef.current; +}; + +const useEncodingQuery = ( + model: Remote | undefined, + selectedMediaItem: Pick | undefined +) => { + return useQuery({ + queryKey: ['segment-anything-model', 'encoding', selectedMediaItem?.id], + queryFn: async () => { + if (model === undefined) { + throw new Error('Model not yet initialized'); + } + + if (selectedMediaItem === undefined) { + throw new Error('Media item not selected'); + } + + return await model.processEncoder(new ImageData(selectedMediaItem.width, selectedMediaItem.height)); + }, + staleTime: Infinity, + gcTime: 3600 * 15, // WIP + enabled: model !== undefined && selectedMediaItem !== undefined, + }); +}; +const useDecodingFn = (model: Remote | undefined, encoding: EncodingOutput | undefined) => { // TODO: look into returning a new "decoder model" instance that already has the encoding data // stored in memory, to reduce memory usage return async (points: InteractiveAnnotationPoint[]) => { @@ -35,7 +96,7 @@ const useDecodingFn = (model: Remote | undefined, encoding points, boxes: [], ouputConfig: { - type: shapeType, + type: 'polygon', }, image: undefined, }); @@ -44,67 +105,14 @@ const useDecodingFn = (model: Remote | undefined, encoding }; }; -const useEncodingQuery = (model: Remote | undefined, mediaItem: MediaItem | undefined) => { - return useQuery({ - queryKey: ['segment-anything-model', 'encoding', mediaItem?.id], - queryFn: async () => { - if (model === undefined) { - throw new Error('Model not yet initialized'); - } - - if (mediaItem === undefined) { - throw new Error('Media item not selected'); - } - - return await model.processEncoder(new ImageData(mediaItem.width, mediaItem.height)); - }, - staleTime: Infinity, - gcTime: 3600 * 15, - enabled: model !== undefined && mediaItem !== undefined, - }); -}; - -const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'SEGMENT_ANYTHING_ENCODER') => { - const worker = useSegmentAnythingWorkerQuery(algorithmType); - - const [model, setModel] = useState | undefined>(undefined); - const [modelIsLoading, setModelIsLoading] = useState(false); - - useEffect(() => { - const loadWorker = async () => { - setModelIsLoading(true); - - if (worker) { - const modelInstance = worker.data; - - if (modelInstance) { - await modelInstance.init(algorithmType); - - setModel(modelInstance); - } - } - - setModelIsLoading(false); - }; - - if (worker && model === undefined && !modelIsLoading) { - loadWorker(); - } - }, [worker, modelIsLoading, algorithmType, model]); - - return model; -}; - export const useSegmentAnythingModel = () => { const encoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_ENCODER'); const decoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_DECODER'); - const { mediaItem } = useAnnotator(); const isLoading = encoderModel === undefined || decoderModel === undefined; + const { mediaItem } = useAnnotator(); const encodingQuery = useEncodingQuery(encoderModel, mediaItem); const decodingQueryFn = useDecodingFn(decoderModel, encodingQuery.data); - useEncodingQuery(encoderModel, encodingQuery.isFetching ? undefined : mediaItem); - return { isLoading, encodingQuery, decodingQueryFn }; }; From 08c47c845d6470512153bd1b96c1d9db2d0ef6eb Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 10:19:10 +0200 Subject: [PATCH 08/29] Fix tool render without annotations --- .../features/annotator/annotator-canvas.tsx | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index 16c057cae6..af9c0b0be7 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -51,20 +51,19 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) Collected data - {!isEmpty(annotations) && ( - - + + + {!isEmpty(annotations) && ( - - - - - )} + )} + + + From ad796aa235af58a1fa7f94e5ea9938109e8055ab Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 10:29:16 +0200 Subject: [PATCH 09/29] Fix TODO; Remove unused secondary toolbar --- .../secondary-toolbar.component.tsx | 136 ------------------ .../use-decoding-query.hook.ts | 5 +- 2 files changed, 2 insertions(+), 139 deletions(-) delete mode 100644 ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx diff --git a/ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx deleted file mode 100644 index 2880c0fba3..0000000000 --- a/ui/src/features/annotator/tools/segment-anything-tool/secondary-toolbar.component.tsx +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (C) 2025 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -import { Button, Divider, Flex, Loading, Switch, Text, Tooltip, TooltipTrigger, useMediaQuery, View } from '@geti/ui'; -import { RightClick } from '@geti/ui/icons'; -import { isLargeSizeQuery } from '@geti/ui/theme'; - -import { useSegmentAnything } from './segment-anything-state-provider.component'; - -const INTERACTIVE_MODE_TOOLTIP = 'With this mode ON, edit preview by placing new positive or negative points. - SHIFT'; - -const RIGHT_CLICK_MODE_TOOLTIP = - 'With this mode ON, press left-click to place positive points and right-click to place negative points.'; - -// TODO: replace by actual tool settings -const toolSettings = { - interactiveMode: false, - rightClickMode: false, - maskOpacity: 0.5, -}; - -export const SecondaryToolbar = () => { - const isLargeSize = useMediaQuery(isLargeSizeQuery); - - const { points, isLoading, encodingQuery } = useSegmentAnything(); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const handleOnChange = (_value: number) => { - // TODO: Update tool settings - // updateToolSettings(ToolType.SegmentAnythingTool, { ...toolSettings, maskOpacity: value }); - }; - - const setToolSetting = (_data: unknown) => { - // TODO: Update tool settings - // updateToolSettings(ToolType.SegmentAnythingTool, { ...toolSettings, ...data }); - }; - - if (isLoading || encodingQuery.data === undefined) { - return ( - - {isLargeSize && ( - <> - Auto segmentation - - - )} - - - {isLoading ? 'Loading image model' : 'Extracting image features'} - - ); - } - - return ( - - {isLargeSize && ( - <> - Auto segmentation - - - )} - - - setToolSetting({ interactiveMode })} - height='100%' - aria-label='Interactive mode' - isDisabled={toolSettings.interactiveMode === true && points.length > 0} - > - Interactive mode - - {INTERACTIVE_MODE_TOOLTIP} - - - - - - - setToolSetting({ rightClickMode: val })} - height='100%' - aria-label='Right-click mode' - > - - Right-click mode - - - - - - - {RIGHT_CLICK_MODE_TOOLTIP} - - - - - - {/* - `${Math.round(100 * value)}%`} - label={'Mask opacity'} - ariaLabel='Mask opacity' - min={0} - max={1} - step={0.01} - onChange={handleOnChange} - value={toolSettings.maskOpacity} - /> - Adjust the opacity - */} - - {points.length > 0 && ( - <> - - - - - - - )} - - ); -}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts index c26154451f..230838d88e 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts @@ -52,6 +52,7 @@ export const useDecodingQuery = ( }; export const useDecodingMutation = (queryFn: (points: InteractiveAnnotationPoint[]) => Promise) => { + const { addAnnotation } = useAnnotator(); return useMutation({ mutationFn: async (points: InteractiveAnnotationPoint[]) => { // Round points so that when the user slightly moves their mouse we do not @@ -62,14 +63,12 @@ export const useDecodingMutation = (queryFn: (points: InteractiveAnnotationPoint positive: point.positive, })); - // TODO: Add callback to add shapes - // eslint-disable-next-line @typescript-eslint/no-unused-vars const shapes = (await queryFn(roundedPoints)).map((shape) => { return removeOffLimitPoints(shape, roi); }); // Add the shapes to the canvas here - // addShapes(shapes); + shapes.map((shape) => addAnnotation(shape)); }, }); }; From 19148ed992c10df8244ebdc85f99e7c37f59ceee Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 10:45:54 +0200 Subject: [PATCH 10/29] Replace mocked roi for media item one --- .../segment-anything-tool.component.tsx | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 76ad4541c5..ea83095010 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -1,7 +1,7 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { PointerEvent, useEffect, useRef, useState } from 'react'; +import { PointerEvent, useEffect, useMemo, useRef, useState } from 'react'; import { clampPointBetweenImage, isPointInShape, pointInRectangle } from '@geti/smart-tools/utils'; @@ -9,7 +9,7 @@ import { useZoom } from '../../../../components/zoom/zoom'; import { AnnotationShape } from '../../annotations/annotation-shape.component'; import { MaskAnnotations } from '../../annotations/mask-annotations.component'; import { useAnnotator } from '../../annotator-provider.component'; -import { Annotation, Point, RegionOfInterest, Shape } from '../../types'; +import { Annotation, Point, Shape } from '../../types'; import { isRightButton } from '../../utils'; import { getRelativePoint, removeOffLimitPoints } from '../utils'; import { InteractiveSegmentationPoint } from './interactive-segmentation-point.component'; @@ -35,13 +35,6 @@ const isPositivePoint = (point: Point, shapes: Shape[], isRightClick: boolean, r // the user's cpu with too many decoding requests const THROTTLE_TIME = 150; -const roi: RegionOfInterest = { - x: 0, - y: 0, - width: 100, - height: 100, -}; - const toolSettings = { interactiveMode: false, rightClickMode: false, @@ -57,6 +50,7 @@ const SELECT_ANNOTATION_STYLES = { export const SegmentAnythingTool = () => { const zoom = useZoom(); const { mediaItem } = useAnnotator(); + const roi = useMemo(() => ({ x: 0, y: 0, width: mediaItem.width, height: mediaItem.height }), [mediaItem]); const clampPoint = clampPointBetweenImage(new ImageData(mediaItem.width, mediaItem.height)); @@ -89,7 +83,7 @@ export const SegmentAnythingTool = () => { // start to compute the next decoding return []; }); - }, [mousePosition, throttledDecodingQueryFn, throttleSetMousePosition]); + }, [mousePosition, throttledDecodingQueryFn, throttleSetMousePosition, roi]); const { interactiveMode, rightClickMode } = toolSettings; @@ -100,11 +94,6 @@ export const SegmentAnythingTool = () => { const point = clampPoint(getRelativePoint(ref.current, { x: event.clientX, y: event.clientY }, zoom.scale)); - // In task chain don't allow the user to place a point outside the ROI - if (!pointInRectangle(roi, point)) { - return; - } - const positive = isPositivePoint(point, result.shapes, isRightButton(event), rightClickMode); throttleSetMousePosition({ ...point, positive }); From 264fe252011afea489041799e230176ba446e5ea Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 11:05:43 +0200 Subject: [PATCH 11/29] Add ModelLoading --- .../segment-anything-tool.component.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index ea83095010..d43afa0c65 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -13,6 +13,7 @@ import { Annotation, Point, Shape } from '../../types'; import { isRightButton } from '../../utils'; import { getRelativePoint, removeOffLimitPoints } from '../utils'; import { InteractiveSegmentationPoint } from './interactive-segmentation-point.component'; +import { ModelLoading } from './model-loading.component'; import { useSegmentAnything } from './segment-anything-state-provider.component'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; import { useSingleStackFn } from './use-single-stack-fn.hook'; @@ -56,7 +57,7 @@ export const SegmentAnythingTool = () => { const ref = useRef(null); - const { result, points, addPoint } = useSegmentAnything(); + const { result, points, addPoint, isLoading, encodingQuery } = useSegmentAnything(); const [mousePosition, setMousePosition] = useState(); const [previewShapes, setPreviewShapes] = useState([]); @@ -144,6 +145,10 @@ export const SegmentAnythingTool = () => { }; }); + if (isLoading || encodingQuery.data === undefined) { + return ; + } + return ( Date: Fri, 19 Sep 2025 11:54:53 +0200 Subject: [PATCH 12/29] Add svgtoolcanvas; Add imageData utils; Replace black square with actual image --- .../annotator-provider.component.tsx | 9 +++- .../hooks/use-load-image-query.hook.ts | 26 ++++++++++ ...ment-anything-state-provider.component.tsx | 5 ++ .../segment-anything-tool.component.tsx | 7 ++- .../use-decoding-query.hook.ts | 14 ++--- .../use-segment-anything.hook.ts | 21 ++++---- .../tools/svg-tool-canvas.component.tsx | 35 +++++++++++++ ui/src/features/annotator/tools/utils.ts | 51 +++++++++++++++++++ 8 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 ui/src/features/annotator/hooks/use-load-image-query.hook.ts create mode 100644 ui/src/features/annotator/tools/svg-tool-canvas.component.tsx diff --git a/ui/src/features/annotator/annotator-provider.component.tsx b/ui/src/features/annotator/annotator-provider.component.tsx index f0b514a76d..e003747d19 100644 --- a/ui/src/features/annotator/annotator-provider.component.tsx +++ b/ui/src/features/annotator/annotator-provider.component.tsx @@ -6,7 +6,8 @@ import { createContext, Dispatch, ReactNode, SetStateAction, useContext, useStat import { v4 as uuid } from 'uuid'; import { ToolType } from '../../components/tool-selection-bar/tools/interface'; -import { Annotation, DatasetItem, Shape } from './types'; +import { useLoadImageQuery } from './hooks/use-load-image-query.hook'; +import { Annotation, DatasetItem, RegionOfInterest, Shape } from './types'; type AnnotatorContext = { activeTool: ToolType | null; @@ -16,6 +17,8 @@ type AnnotatorContext = { updateAnnotation: (updatedAnnotation: Annotation) => void; mediaItem: DatasetItem; + image: ImageData; + roi: RegionOfInterest; annotations: Annotation[]; }; @@ -26,6 +29,8 @@ export const AnnotatorProvider = ({ mediaItem, children }: { mediaItem: DatasetI // todo: pass media annotations const [annotations, setAnnotations] = useState([]); + const imageQuery = useLoadImageQuery(mediaItem); + const updateAnnotation = (updatedAnnotation: Annotation) => { const { id } = updatedAnnotation; @@ -57,6 +62,8 @@ export const AnnotatorProvider = ({ mediaItem, children }: { mediaItem: DatasetI annotations, mediaItem, + image: imageQuery.data || new ImageData(mediaItem.width, mediaItem.height), + roi: { x: 0, y: 0, width: mediaItem.width, height: mediaItem.height }, }} > {children} diff --git a/ui/src/features/annotator/hooks/use-load-image-query.hook.ts b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts new file mode 100644 index 0000000000..43ab0ba141 --- /dev/null +++ b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts @@ -0,0 +1,26 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { useQuery, UseQueryResult } from '@tanstack/react-query'; + +import { getImageData, loadImage } from '../tools/utils'; +import { MediaItem } from '../types'; + +export const useLoadImageQuery = (mediaItem: MediaItem | undefined): UseQueryResult => { + return useQuery({ + queryKey: ['mediaItem', mediaItem?.id], + queryFn: async () => { + if (mediaItem === undefined) { + throw new Error("Can't fetch undefined media item"); + } + + const image = await loadImage(mediaItem.thumbhash); + + return getImageData(image); + }, + enabled: mediaItem !== undefined, + // The image of a media item never changes so we don't want to refetch stale data + staleTime: Infinity, + retry: 0, + }); +}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx index c237f62e60..dc1690b7f1 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -10,6 +10,7 @@ import { isEmpty } from 'lodash-es'; import { useAnnotator } from '../../annotator-provider.component'; import { Shape } from '../../types'; +import { ModelLoading } from './model-loading.component'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; import { useDecodingMutation, useDecodingQuery, useDecodingQueryOptions } from './use-decoding-query.hook'; import { useSegmentAnythingModel } from './use-segment-anything.hook'; @@ -108,6 +109,10 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode } }; + if (isLoading || encodingQuery.data === undefined) { + return ; + } + return ( { const zoom = useZoom(); - const { mediaItem } = useAnnotator(); - const roi = useMemo(() => ({ x: 0, y: 0, width: mediaItem.width, height: mediaItem.height }), [mediaItem]); + const { mediaItem, roi, image } = useAnnotator(); - const clampPoint = clampPointBetweenImage(new ImageData(mediaItem.width, mediaItem.height)); + const clampPoint = clampPointBetweenImage(image); const ref = useRef(null); diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts index 230838d88e..504c5586b9 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts @@ -4,22 +4,15 @@ import { queryOptions, useMutation, useQuery } from '@tanstack/react-query'; import { useAnnotator } from '../../annotator-provider.component'; -import { RegionOfInterest, Shape } from '../../types'; +import { Shape } from '../../types'; import { removeOffLimitPoints } from '../utils'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; -const roi: RegionOfInterest = { - x: 0, - y: 0, - width: 100, - height: 100, -}; - export const useDecodingQueryOptions = ( points: InteractiveAnnotationPoint[], queryFn: (points: InteractiveAnnotationPoint[]) => Promise ) => { - const { mediaItem } = useAnnotator(); + const { mediaItem, roi } = useAnnotator(); // Round points so that when the user slightly moves their mouse we do not // immediately recompute the decoding const roundedPoints = points.map((point) => ({ @@ -52,7 +45,8 @@ export const useDecodingQuery = ( }; export const useDecodingMutation = (queryFn: (points: InteractiveAnnotationPoint[]) => Promise) => { - const { addAnnotation } = useAnnotator(); + const { addAnnotation, roi } = useAnnotator(); + return useMutation({ mutationFn: async (points: InteractiveAnnotationPoint[]) => { // Round points so that when the user slightly moves their mouse we do not diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts index c1aac4938f..c4b4ed6dc6 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts @@ -53,26 +53,23 @@ const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'S return modelRef.current; }; -const useEncodingQuery = ( - model: Remote | undefined, - selectedMediaItem: Pick | undefined -) => { +const useEncodingQuery = (model: Remote | undefined, mediaItem: MediaItem, image: ImageData) => { return useQuery({ - queryKey: ['segment-anything-model', 'encoding', selectedMediaItem?.id], + queryKey: ['segment-anything-model', 'encoding', mediaItem?.id], queryFn: async () => { if (model === undefined) { throw new Error('Model not yet initialized'); } - if (selectedMediaItem === undefined) { - throw new Error('Media item not selected'); + if (image === undefined) { + throw new Error('Image not available'); } - return await model.processEncoder(new ImageData(selectedMediaItem.width, selectedMediaItem.height)); + return await model.processEncoder(image); }, staleTime: Infinity, - gcTime: 3600 * 15, // WIP - enabled: model !== undefined && selectedMediaItem !== undefined, + gcTime: 3600 * 15, + enabled: model !== undefined && mediaItem !== undefined, }); }; @@ -110,8 +107,8 @@ export const useSegmentAnythingModel = () => { const decoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_DECODER'); const isLoading = encoderModel === undefined || decoderModel === undefined; - const { mediaItem } = useAnnotator(); - const encodingQuery = useEncodingQuery(encoderModel, mediaItem); + const { mediaItem, image } = useAnnotator(); + const encodingQuery = useEncodingQuery(encoderModel, mediaItem, image); const decodingQueryFn = useDecodingFn(decoderModel, encodingQuery.data); return { isLoading, encodingQuery, decodingQueryFn }; diff --git a/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx b/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx new file mode 100644 index 0000000000..551aee820b --- /dev/null +++ b/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx @@ -0,0 +1,35 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { FC, PropsWithChildren, RefObject, SVGProps } from 'react'; + +import { roiFromImage } from '@geti/smart-tools/utils'; + +import { allowPanning } from '../utils'; + +type CanvasProps = SVGProps & { image: ImageData } & { canvasRef?: RefObject }; +// This svg component is used to by tools that need to add local listeners that work in +// a given region of interest. +// An invisible rect is rendered to guarantee that the svg gets a width and height. +export const SvgToolCanvas: FC> = ({ + image, + children, + canvasRef, + onPointerDown, + ...props +}) => { + const roi = roiFromImage(image); + + return ( + + + {children} + + ); +}; diff --git a/ui/src/features/annotator/tools/utils.ts b/ui/src/features/annotator/tools/utils.ts index 0afb531bb6..cbb227741c 100644 --- a/ui/src/features/annotator/tools/utils.ts +++ b/ui/src/features/annotator/tools/utils.ts @@ -339,3 +339,54 @@ export const getRelativePoint = (element: ElementType, point: Point, zoom: numbe y: Math.round((point.y - rect.top) / zoom), }; }; + +export const loadImage = (link: string): Promise => + new Promise((resolve, reject) => { + const image = new Image(); + image.crossOrigin = 'use-credentials'; + + image.onload = () => resolve(image); + image.onerror = (error) => reject(error); + + image.fetchPriority = 'high'; + image.src = link; + + if (process.env.NODE_ENV === 'test') { + // Immediately load the media item's image + resolve(image); + } + }); + +const drawImageOnCanvas = (img: HTMLImageElement, filter = ''): HTMLCanvasElement => { + const canvas: HTMLCanvasElement = document.createElement('canvas'); + + canvas.width = img.naturalWidth ? img.naturalWidth : img.width; + canvas.height = img.naturalHeight ? img.naturalHeight : img.height; + + const ctx = canvas.getContext('2d'); + + if (ctx) { + const width = img.naturalWidth ? img.naturalWidth : img.width; + const height = img.naturalHeight ? img.naturalHeight : img.height; + + ctx.filter = filter; + ctx.drawImage(img, 0, 0, width, height); + } + + return canvas; +}; + +export const getImageData = (img: HTMLImageElement): ImageData => { + // Always return valid imageData, even if the image isn't loaded yet. + if (img.width === 0 && img.height === 0) { + return new ImageData(1, 1); + } + + const canvas = drawImageOnCanvas(img); + const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; + + const width = img.naturalWidth ? img.naturalWidth : img.width; + const height = img.naturalHeight ? img.naturalHeight : img.height; + + return ctx.getImageData(0, 0, width, height); +}; From 644658a642b73089d7137e5b43f9b34cacdc1ea1 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 14:10:08 +0200 Subject: [PATCH 13/29] More fixes --- .../features/annotator/annotator-canvas.tsx | 2 +- ...teractive-segmentation-point.component.tsx | 4 +- .../segment-anything-tool.component.tsx | 58 ++++++++++++++++--- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index af9c0b0be7..e9f816c34a 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -51,7 +51,7 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) Collected data - + { const fill = positive ? 'var(--brand-moss)' : 'var(--brand-coral-cobalt)'; - const radius = `1 / var(--zoom-scale)`; + const radius = `calc(1 / var(--zoom-scale))`; return ( <> { const ref = useRef(null); - const { result, points, addPoint, isLoading, encodingQuery } = useSegmentAnything(); + const { result, points, addPoint } = useSegmentAnything(); const [mousePosition, setMousePosition] = useState(); const [previewShapes, setPreviewShapes] = useState([]); @@ -139,17 +139,15 @@ export const SegmentAnythingTool = () => { const annotations = (showPreviewShapes ? previewShapes : result.shapes).map((shape, idx): Annotation => { return { shape, - labels: [{ id: `sam-${idx}`, name: 'SAM', color: 'var(--energy-blue-shade)', isPrediction: true }], + labels: [{ id: 'id', color: 'red', name: 'Segment Anything', isPrediction: false }], id: `${idx}`, }; }); - if (isLoading || encodingQuery.data === undefined) { - return ; - } - return ( - { @@ -193,6 +191,48 @@ export const SegmentAnythingTool = () => { })} + {showPreviewShapes && + previewShapes.map((shape, idx) => ( + + + + ))} + + {result.shapes.map((shape, idx) => ( + + + + ))} + {points.map((point, index) => ( { isLoading={false} /> ))} - + ); }; From 8b10f69cd01ed668aa34ead72dccda5401600938 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 14:43:01 +0200 Subject: [PATCH 14/29] Fix CSP headers & image url --- ui/rsbuild.config.ts | 3 ++- .../annotator/hooks/use-load-image-query.hook.ts | 14 +++++++++----- .../use-segment-anything.hook.ts | 8 ++++++-- ui/src/features/annotator/tools/utils.ts | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ui/rsbuild.config.ts b/ui/rsbuild.config.ts index fb45a56769..8dcb046531 100644 --- a/ui/rsbuild.config.ts +++ b/ui/rsbuild.config.ts @@ -55,13 +55,14 @@ export default defineConfig({ }, server: { headers: { - 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Cross-Origin-Embedder-Policy': 'credentialless', 'Cross-Origin-Opener-Policy': 'same-origin', 'Content-Security-Policy': "default-src 'self'; " + "script-src 'self' 'unsafe-eval' blob:; " + "worker-src 'self' blob:; " + "connect-src 'self' http://localhost:7860 data:; " + + "img-src 'self' http://localhost:7860 data: blob:; " + "style-src 'self' 'unsafe-inline';", }, }, diff --git a/ui/src/features/annotator/hooks/use-load-image-query.hook.ts b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts index 43ab0ba141..4d1a35a65f 100644 --- a/ui/src/features/annotator/hooks/use-load-image-query.hook.ts +++ b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts @@ -3,22 +3,26 @@ import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { useProjectIdentifier } from '../../../hooks/use-project-identifier.hook'; import { getImageData, loadImage } from '../tools/utils'; -import { MediaItem } from '../types'; +import { DatasetItem } from '../types'; + +export const useLoadImageQuery = (mediaItem: DatasetItem | undefined): UseQueryResult => { + const projectId = useProjectIdentifier(); -export const useLoadImageQuery = (mediaItem: MediaItem | undefined): UseQueryResult => { return useQuery({ - queryKey: ['mediaItem', mediaItem?.id], + queryKey: ['mediaItem', mediaItem?.id, projectId], queryFn: async () => { if (mediaItem === undefined) { throw new Error("Can't fetch undefined media item"); } - const image = await loadImage(mediaItem.thumbhash); + const imageUrl = `http://localhost:7860/api/projects/${projectId}/dataset/items/${mediaItem.id}/binary`; + const image = await loadImage(imageUrl); return getImageData(image); }, - enabled: mediaItem !== undefined, + enabled: mediaItem !== undefined && !!projectId, // The image of a media item never changes so we don't want to refetch stale data staleTime: Infinity, retry: 0, diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts index c4b4ed6dc6..bfea1cba5f 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts @@ -8,7 +8,7 @@ import { useQuery } from '@tanstack/react-query'; import { Remote, wrap } from 'comlink'; import { useAnnotator } from '../../annotator-provider.component'; -import { MediaItem } from '../../types'; +import { DatasetItem } from '../../types'; import { convertToolShapeToGetiShape } from '../utils'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; @@ -53,7 +53,11 @@ const useSegmentAnythingWorker = (algorithmType: 'SEGMENT_ANYTHING_DECODER' | 'S return modelRef.current; }; -const useEncodingQuery = (model: Remote | undefined, mediaItem: MediaItem, image: ImageData) => { +const useEncodingQuery = ( + model: Remote | undefined, + mediaItem: DatasetItem, + image: ImageData +) => { return useQuery({ queryKey: ['segment-anything-model', 'encoding', mediaItem?.id], queryFn: async () => { diff --git a/ui/src/features/annotator/tools/utils.ts b/ui/src/features/annotator/tools/utils.ts index cbb227741c..ce3c755e13 100644 --- a/ui/src/features/annotator/tools/utils.ts +++ b/ui/src/features/annotator/tools/utils.ts @@ -343,7 +343,7 @@ export const getRelativePoint = (element: ElementType, point: Point, zoom: numbe export const loadImage = (link: string): Promise => new Promise((resolve, reject) => { const image = new Image(); - image.crossOrigin = 'use-credentials'; + image.crossOrigin = 'anonymous'; image.onload = () => resolve(image); image.onerror = (error) => reject(error); From 9fb1f476d73f6d22079222f1aafb7a24516e0644 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Fri, 19 Sep 2025 15:28:52 +0200 Subject: [PATCH 15/29] Update loading logic; Expose loading from annotator --- ui/src/features/annotator/annotator-canvas.tsx | 5 +++++ .../annotator/annotator-provider.component.tsx | 13 ++++++++++++- ...oading.component.tsx => loading.component.tsx} | 7 +++---- .../segment-anything-state-provider.component.tsx | 15 +++++++++------ 4 files changed, 29 insertions(+), 11 deletions(-) rename ui/src/features/annotator/{tools/segment-anything-tool/model-loading.component.tsx => loading.component.tsx} (82%) diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index e9f816c34a..691e5f5679 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -11,6 +11,8 @@ import { ZoomTransform } from '../../components/zoom/zoom-transform'; import { useProjectIdentifier } from '../../hooks/use-project-identifier.hook'; import { getImageUrl } from '../dataset/gallery/utils'; import { Annotations } from './annotations/annotations.component'; +import { useAnnotator } from './annotator-provider.component'; +import { Loading } from './loading.component'; import { useSelectedAnnotations } from './select-annotation-provider.component'; import { ToolManager } from './tools/tool-manager.component'; import { Annotation, DatasetItem } from './types'; @@ -33,6 +35,7 @@ type AnnotatorCanvasProps = { export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) => { const { setSelectedAnnotations } = useSelectedAnnotations(); const project_id = useProjectIdentifier(); + const { isLoading } = useAnnotator(); const size = { width: mediaItem.width, height: mediaItem.height }; // todo: pass media annotations const annotations: Annotation[] = []; @@ -63,6 +66,8 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) )} + + {isLoading && } diff --git a/ui/src/features/annotator/annotator-provider.component.tsx b/ui/src/features/annotator/annotator-provider.component.tsx index e003747d19..2dfc9bf845 100644 --- a/ui/src/features/annotator/annotator-provider.component.tsx +++ b/ui/src/features/annotator/annotator-provider.component.tsx @@ -10,16 +10,23 @@ import { useLoadImageQuery } from './hooks/use-load-image-query.hook'; import { Annotation, DatasetItem, RegionOfInterest, Shape } from './types'; type AnnotatorContext = { + // Tools activeTool: ToolType | null; setActiveTool: Dispatch>; + // Annotations + annotations: Annotation[]; addAnnotation: (shape: Shape) => void; updateAnnotation: (updatedAnnotation: Annotation) => void; + // Media item mediaItem: DatasetItem; image: ImageData; roi: RegionOfInterest; - annotations: Annotation[]; + + // Any loading state needed + isLoading: boolean; + setIsLoading: Dispatch>; }; export const AnnotatorProviderContext = createContext(null); @@ -28,6 +35,7 @@ export const AnnotatorProvider = ({ mediaItem, children }: { mediaItem: DatasetI const [activeTool, setActiveTool] = useState('selection'); // todo: pass media annotations const [annotations, setAnnotations] = useState([]); + const [isLoading, setIsLoading] = useState(false); const imageQuery = useLoadImageQuery(mediaItem); @@ -64,6 +72,9 @@ export const AnnotatorProvider = ({ mediaItem, children }: { mediaItem: DatasetI mediaItem, image: imageQuery.data || new ImageData(mediaItem.width, mediaItem.height), roi: { x: 0, y: 0, width: mediaItem.width, height: mediaItem.height }, + + isLoading, + setIsLoading, }} > {children} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/model-loading.component.tsx b/ui/src/features/annotator/loading.component.tsx similarity index 82% rename from ui/src/features/annotator/tools/segment-anything-tool/model-loading.component.tsx rename to ui/src/features/annotator/loading.component.tsx index 8e881dc682..0b8432be49 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/model-loading.component.tsx +++ b/ui/src/features/annotator/loading.component.tsx @@ -3,12 +3,11 @@ import { Flex, Heading, View } from '@geti/ui'; -import IntelBrandedLoadingGif from '../../../../assets/intel-loading.webp'; +import IntelBrandedLoadingGif from '../../assets/intel-loading.webp'; -export const ModelLoading = ({ isLoadingModel }: { isLoadingModel: boolean }) => { +export const Loading = ({ isLoading }: { isLoading: boolean }) => { return ( textShadow: '1px 1px 2px black, 1px 1px 2px white', }} > - {isLoadingModel ? 'Loading image model' : 'Extracting image features'} + {isLoading && 'Processing image, please wait...'} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx index dc1690b7f1..5ea7fffd8b 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -10,7 +10,6 @@ import { isEmpty } from 'lodash-es'; import { useAnnotator } from '../../annotator-provider.component'; import { Shape } from '../../types'; -import { ModelLoading } from './model-loading.component'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; import { useDecodingMutation, useDecodingQuery, useDecodingQueryOptions } from './use-decoding-query.hook'; import { useSegmentAnythingModel } from './use-segment-anything.hook'; @@ -42,7 +41,7 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode }); const [_, setIsDrawing] = useState(false); - const { addAnnotation } = useAnnotator(); + const { addAnnotation, setIsLoading } = useAnnotator(); const queryClient = useQueryClient(); const { encodingQuery, decodingQueryFn, isLoading } = useSegmentAnythingModel(); @@ -65,6 +64,14 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode const decodingMutation = useDecodingMutation(decodingQueryFn); + useEffect(() => { + if (isLoading) { + setIsLoading(true); + } else if (encodingQuery.data !== undefined) { + setIsLoading(false); + } + }, [isLoading, encodingQuery.data, setIsLoading]); + const reset = async () => { queryClient.removeQueries({ queryKey: decodingQueryOptions.queryKey }); @@ -109,10 +116,6 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode } }; - if (isLoading || encodingQuery.data === undefined) { - return ; - } - return ( Date: Fri, 19 Sep 2025 15:37:49 +0200 Subject: [PATCH 16/29] Add missing icons --- ui/src/assets/icons/pencil-minus.svg | 8 ++++++++ ui/src/assets/icons/pencil-plus copy.svg | 8 ++++++++ .../segment-anything-tool.component.tsx | 4 ++-- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 ui/src/assets/icons/pencil-minus.svg create mode 100644 ui/src/assets/icons/pencil-plus copy.svg diff --git a/ui/src/assets/icons/pencil-minus.svg b/ui/src/assets/icons/pencil-minus.svg new file mode 100644 index 0000000000..4b486d6cab --- /dev/null +++ b/ui/src/assets/icons/pencil-minus.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/ui/src/assets/icons/pencil-plus copy.svg b/ui/src/assets/icons/pencil-plus copy.svg new file mode 100644 index 0000000000..ea88f630b6 --- /dev/null +++ b/ui/src/assets/icons/pencil-plus copy.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 89c148314e..8efde8cd0c 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -37,7 +37,7 @@ const isPositivePoint = (point: Point, shapes: Shape[], isRightClick: boolean, r const THROTTLE_TIME = 150; const toolSettings = { - interactiveMode: false, + interactiveMode: true, rightClickMode: false, }; @@ -171,7 +171,7 @@ export const SegmentAnythingTool = () => { strokeWidth={'calc(3px / var(--zoom-level))'} cursor={ !showPreviewShapes - ? `url(/icons/cursor/pencil-${ + ? `url(/icons/pencil-${ interactiveMode === true && rightClickMode === false ? 'minus' : 'plus' }.svg) 16 16, auto` : undefined From 037a772329f084d91876aa86a91f1d23881646aa Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Mon, 22 Sep 2025 08:51:09 +0200 Subject: [PATCH 17/29] Address comment --- ui/src/features/annotator/annotator-canvas.tsx | 4 ++-- .../annotator/hooks/use-load-image-query.hook.ts | 5 +++-- ui/src/features/annotator/loading.component.tsx | 4 ++-- .../interactive-segmentation-point.component.tsx | 10 +++++++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index 691e5f5679..bba6fb92bc 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -12,7 +12,7 @@ import { useProjectIdentifier } from '../../hooks/use-project-identifier.hook'; import { getImageUrl } from '../dataset/gallery/utils'; import { Annotations } from './annotations/annotations.component'; import { useAnnotator } from './annotator-provider.component'; -import { Loading } from './loading.component'; +import { AnnotatorLoading } from './loading.component'; import { useSelectedAnnotations } from './select-annotation-provider.component'; import { ToolManager } from './tools/tool-manager.component'; import { Annotation, DatasetItem } from './types'; @@ -67,7 +67,7 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) - {isLoading && } + {isLoading && } diff --git a/ui/src/features/annotator/hooks/use-load-image-query.hook.ts b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts index 4d1a35a65f..cf06d8a6f4 100644 --- a/ui/src/features/annotator/hooks/use-load-image-query.hook.ts +++ b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts @@ -3,6 +3,7 @@ import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { API_BASE_URL } from '../../../api/client'; import { useProjectIdentifier } from '../../../hooks/use-project-identifier.hook'; import { getImageData, loadImage } from '../tools/utils'; import { DatasetItem } from '../types'; @@ -17,12 +18,12 @@ export const useLoadImageQuery = (mediaItem: DatasetItem | undefined): UseQueryR throw new Error("Can't fetch undefined media item"); } - const imageUrl = `http://localhost:7860/api/projects/${projectId}/dataset/items/${mediaItem.id}/binary`; + const imageUrl = `${API_BASE_URL}/api/projects/${projectId}/dataset/items/${mediaItem.id}/binary`; const image = await loadImage(imageUrl); return getImageData(image); }, - enabled: mediaItem !== undefined && !!projectId, + enabled: mediaItem !== undefined && Boolean(projectId), // The image of a media item never changes so we don't want to refetch stale data staleTime: Infinity, retry: 0, diff --git a/ui/src/features/annotator/loading.component.tsx b/ui/src/features/annotator/loading.component.tsx index 0b8432be49..6b15cbc657 100644 --- a/ui/src/features/annotator/loading.component.tsx +++ b/ui/src/features/annotator/loading.component.tsx @@ -5,7 +5,7 @@ import { Flex, Heading, View } from '@geti/ui'; import IntelBrandedLoadingGif from '../../assets/intel-loading.webp'; -export const Loading = ({ isLoading }: { isLoading: boolean }) => { +export const AnnotatorLoading = ({ isLoading }: { isLoading: boolean }) => { return ( { src={IntelBrandedLoadingGif} // eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role role='progressbar' - alt='Extracting image features' + alt='Processing image' style={{ width: 300, height: 300, diff --git a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx index 5b0bdd0979..3e73ecba10 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx @@ -9,14 +9,15 @@ interface InteractiveSegmentationPointProps extends InteractiveAnnotationPoint { export const InteractiveSegmentationPoint = ({ x, y, positive, isLoading }: InteractiveSegmentationPointProps) => { const fill = positive ? 'var(--brand-moss)' : 'var(--brand-coral-cobalt)'; - const radius = `calc(1 / var(--zoom-scale))`; + const animationScale = `calc(1 / var(--zoom-scale))`; + const pointRadius = `calc(5 / var(--zoom-scale))`; return ( <> {isLoading && ( - + Date: Mon, 22 Sep 2025 09:57:40 +0200 Subject: [PATCH 18/29] Fix lock --- ui/package-lock.json | 63 +++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 942ea91bb6..843ca4d48d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -2438,7 +2438,6 @@ "resolved": "https://registry.npmjs.org/@doodle3d/clipper-js/-/clipper-js-1.0.11.tgz", "integrity": "sha512-KSVF9iOl9jGu02EGUnVS2ric4iQRSIypg3/CTM30+MuWsqkUhILIG2EPxvPASENi6483QmNIwGSogZuTE7CFQA==", "license": "MIT", - "peer": true, "dependencies": { "@doodle3d/clipper-lib": "^6.4.2-b" } @@ -2447,8 +2446,7 @@ "version": "6.4.2-b", "resolved": "https://registry.npmjs.org/@doodle3d/clipper-lib/-/clipper-lib-6.4.2-b.tgz", "integrity": "sha512-glELSijsD9b+/0d9iOdasBwqH3s+xPxD59tJ7aXkBx7klugygGOMXn7PB05AdhVyA1OYMj7GUCegaQa7nvLtmQ==", - "license": "BSL", - "peer": true + "license": "BSL" }, "node_modules/@emnapi/core": { "version": "1.5.0", @@ -4027,36 +4025,31 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -4066,36 +4059,31 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@react-aria/actiongroup": { "version": "3.7.20", @@ -13330,8 +13318,7 @@ "version": "1.12.0", "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==", - "license": "SEE LICENSE IN LICENSE.txt", - "peer": true + "license": "SEE LICENSE IN LICENSE.txt" }, "node_modules/flatted": { "version": "3.3.3", @@ -13630,8 +13617,7 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz", "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/harmony-reflect": { "version": "1.6.2", @@ -14753,8 +14739,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/loose-envify": { "version": "1.4.0", @@ -15246,15 +15231,13 @@ "version": "1.16.3", "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.16.3.tgz", "integrity": "sha512-ZZfFzEqBf6YIGwB9PtBLESHI53jMXA+/hn+ACVUbEfPuK2xI5vMGpLPn+idpwCmHsKJNRzRwqV12K+6TQj6tug==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/onnxruntime-web": { "version": "1.16.3", "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.16.3.tgz", "integrity": "sha512-8O1xCG/RcNQNYYWvdiQJSNpncVg78OVOFeV6MYs/jx++/b12oje8gYUzKqz9wR/sXiX/8TCvdyHgEjj5gQGKUg==", "license": "MIT", - "peer": true, "dependencies": { "flatbuffers": "^1.12.0", "guid-typescript": "^1.0.9", @@ -15610,8 +15593,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/playwright": { "version": "1.54.2", @@ -15660,7 +15642,6 @@ "resolved": "https://registry.npmjs.org/polylabel/-/polylabel-1.1.0.tgz", "integrity": "sha512-bxaGcA40sL3d6M4hH72Z4NdLqxpXRsCFk8AITYg6x1rn1Ei3izf00UMLklerBZTO49aPA3CYrIwVulx2Bce2pA==", "license": "ISC", - "peer": true, "dependencies": { "tinyqueue": "^2.0.3" } @@ -15781,7 +15762,6 @@ "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", "hasInstallScript": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -17712,8 +17692,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/tinyrainbow": { "version": "2.0.0", @@ -19126,6 +19105,11 @@ "packages/smart-tools": { "name": "@geti/smart-tools", "version": "1.0.0", + "dependencies": { + "@doodle3d/clipper-js": "~1.0.11", + "onnxruntime-web": "~1.16.3", + "polylabel": "~1.1.0" + }, "devDependencies": { "@geti/config": "*", "@types/node": "^22.15.3", @@ -19136,11 +19120,6 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", "typescript": "^5.8.3" - }, - "peerDependencies": { - "@doodle3d/clipper-js": "~1.0.11", - "onnxruntime-web": "~1.16.3", - "polylabel": "~1.1.0" } }, "packages/smart-tools/node_modules/@eslint/config-array": { From 8aa0640662c7bc3e009d570253f89e921b11cbb0 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Mon, 22 Sep 2025 09:57:51 +0200 Subject: [PATCH 19/29] Update interface --- .../segment-anything-tool/segment-anything.interface.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts index db9c682939..97515742d7 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything.interface.ts @@ -1,8 +1,8 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -export interface InteractiveAnnotationPoint { - x: number; - y: number; +import { Point } from '../../types'; + +export interface InteractiveAnnotationPoint extends Point { positive: boolean; } From 781b9f61589ae11bd4ed5fd15b1d92f4d3c7a5c9 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Mon, 22 Sep 2025 10:13:51 +0200 Subject: [PATCH 20/29] Extract point rouding util --- .../use-decoding-query.hook.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts index 504c5586b9..086777a51f 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts @@ -8,6 +8,12 @@ import { Shape } from '../../types'; import { removeOffLimitPoints } from '../utils'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; +const roundPoint = (point: InteractiveAnnotationPoint): InteractiveAnnotationPoint => ({ + x: Math.round(point.x), + y: Math.round(point.y), + positive: point.positive, +}); + export const useDecodingQueryOptions = ( points: InteractiveAnnotationPoint[], queryFn: (points: InteractiveAnnotationPoint[]) => Promise @@ -15,11 +21,7 @@ export const useDecodingQueryOptions = ( const { mediaItem, roi } = useAnnotator(); // Round points so that when the user slightly moves their mouse we do not // immediately recompute the decoding - const roundedPoints = points.map((point) => ({ - x: Math.round(point.x), - y: Math.round(point.y), - positive: point.positive, - })); + const roundedPoints = points.map(roundPoint); return queryOptions({ queryKey: ['segment-anything-model', 'decoding', mediaItem?.id, roundedPoints, roi], @@ -51,11 +53,7 @@ export const useDecodingMutation = (queryFn: (points: InteractiveAnnotationPoint mutationFn: async (points: InteractiveAnnotationPoint[]) => { // Round points so that when the user slightly moves their mouse we do not // immediately recompute the decoding - const roundedPoints = points.map((point) => ({ - x: Math.round(point.x), - y: Math.round(point.y), - positive: point.positive, - })); + const roundedPoints = points.map(roundPoint); const shapes = (await queryFn(roundedPoints)).map((shape) => { return removeOffLimitPoints(shape, roi); From ded5d71ef7272bc15b63ad89a1e6d0ec00e7eecf Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Mon, 22 Sep 2025 11:00:09 +0200 Subject: [PATCH 21/29] Move loading to the tool itself --- ui/src/features/annotator/annotator-canvas.tsx | 5 ----- .../annotator/annotator-provider.component.tsx | 8 -------- .../segment-anything-state-provider.component.tsx | 10 +--------- .../segment-anything-tool.component.tsx | 11 ++++++++++- 4 files changed, 11 insertions(+), 23 deletions(-) diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index bba6fb92bc..e9f816c34a 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -11,8 +11,6 @@ import { ZoomTransform } from '../../components/zoom/zoom-transform'; import { useProjectIdentifier } from '../../hooks/use-project-identifier.hook'; import { getImageUrl } from '../dataset/gallery/utils'; import { Annotations } from './annotations/annotations.component'; -import { useAnnotator } from './annotator-provider.component'; -import { AnnotatorLoading } from './loading.component'; import { useSelectedAnnotations } from './select-annotation-provider.component'; import { ToolManager } from './tools/tool-manager.component'; import { Annotation, DatasetItem } from './types'; @@ -35,7 +33,6 @@ type AnnotatorCanvasProps = { export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) => { const { setSelectedAnnotations } = useSelectedAnnotations(); const project_id = useProjectIdentifier(); - const { isLoading } = useAnnotator(); const size = { width: mediaItem.width, height: mediaItem.height }; // todo: pass media annotations const annotations: Annotation[] = []; @@ -66,8 +63,6 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) )} - - {isLoading && } diff --git a/ui/src/features/annotator/annotator-provider.component.tsx b/ui/src/features/annotator/annotator-provider.component.tsx index 2dfc9bf845..48812439c6 100644 --- a/ui/src/features/annotator/annotator-provider.component.tsx +++ b/ui/src/features/annotator/annotator-provider.component.tsx @@ -23,10 +23,6 @@ type AnnotatorContext = { mediaItem: DatasetItem; image: ImageData; roi: RegionOfInterest; - - // Any loading state needed - isLoading: boolean; - setIsLoading: Dispatch>; }; export const AnnotatorProviderContext = createContext(null); @@ -35,7 +31,6 @@ export const AnnotatorProvider = ({ mediaItem, children }: { mediaItem: DatasetI const [activeTool, setActiveTool] = useState('selection'); // todo: pass media annotations const [annotations, setAnnotations] = useState([]); - const [isLoading, setIsLoading] = useState(false); const imageQuery = useLoadImageQuery(mediaItem); @@ -72,9 +67,6 @@ export const AnnotatorProvider = ({ mediaItem, children }: { mediaItem: DatasetI mediaItem, image: imageQuery.data || new ImageData(mediaItem.width, mediaItem.height), roi: { x: 0, y: 0, width: mediaItem.width, height: mediaItem.height }, - - isLoading, - setIsLoading, }} > {children} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx index 5ea7fffd8b..c237f62e60 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -41,7 +41,7 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode }); const [_, setIsDrawing] = useState(false); - const { addAnnotation, setIsLoading } = useAnnotator(); + const { addAnnotation } = useAnnotator(); const queryClient = useQueryClient(); const { encodingQuery, decodingQueryFn, isLoading } = useSegmentAnythingModel(); @@ -64,14 +64,6 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode const decodingMutation = useDecodingMutation(decodingQueryFn); - useEffect(() => { - if (isLoading) { - setIsLoading(true); - } else if (encodingQuery.data !== undefined) { - setIsLoading(false); - } - }, [isLoading, encodingQuery.data, setIsLoading]); - const reset = async () => { queryClient.removeQueries({ queryKey: decodingQueryOptions.queryKey }); diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 8efde8cd0c..1e7767dacc 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -9,6 +9,7 @@ import { useZoom } from '../../../../components/zoom/zoom'; import { AnnotationShape } from '../../annotations/annotation-shape.component'; import { MaskAnnotations } from '../../annotations/mask-annotations.component'; import { useAnnotator } from '../../annotator-provider.component'; +import { AnnotatorLoading } from '../../loading.component'; import { Annotation, Point, Shape } from '../../types'; import { isRightButton } from '../../utils'; import { SvgToolCanvas } from '../svg-tool-canvas.component'; @@ -60,7 +61,7 @@ export const SegmentAnythingTool = () => { const [mousePosition, setMousePosition] = useState(); const [previewShapes, setPreviewShapes] = useState([]); - const { decodingQueryFn } = useSegmentAnything(); + const { decodingQueryFn, isLoading } = useSegmentAnything(); const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); const throttleSetMousePosition = useThrottledCallback((point: InteractiveAnnotationPoint) => { @@ -144,6 +145,14 @@ export const SegmentAnythingTool = () => { }; }); + if (isLoading) { + return ( + + + + ); + } + return ( Date: Mon, 22 Sep 2025 11:47:58 +0200 Subject: [PATCH 22/29] Move svg wrapper to children --- .../annotations/annotations.component.tsx | 25 ++++++++++++---- .../features/annotator/annotator-canvas.tsx | 30 ++----------------- .../segment-anything-tool.component.tsx | 6 +--- .../tools/svg-tool-canvas.component.tsx | 12 +++++++- 4 files changed, 34 insertions(+), 39 deletions(-) diff --git a/ui/src/features/annotator/annotations/annotations.component.tsx b/ui/src/features/annotator/annotations/annotations.component.tsx index a6a7b07af0..c5f7202a65 100644 --- a/ui/src/features/annotator/annotations/annotations.component.tsx +++ b/ui/src/features/annotator/annotations/annotations.component.tsx @@ -1,6 +1,8 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 +import { CSSProperties } from 'react'; + import { useAnnotator } from '../annotator-provider.component'; import { useSelectedAnnotations } from '../select-annotation-provider.component'; import { Annotation } from './annotation.component'; @@ -12,6 +14,17 @@ type AnnotationsProps = { isFocussed: boolean; }; +const DEFAULT_ANNOTATION_STYLES = { + fillOpacity: 0.4, + fill: 'var(--annotation-fill)', + stroke: 'var(--annotation-stroke)', + strokeLinecap: 'round', + strokeWidth: 'calc(1px / var(--zoom-scale))', + strokeDashoffset: 0, + strokeDasharray: 0, + strokeOpacity: 'var(--annotation-border-opacity, 1)', +} satisfies CSSProperties; + export const Annotations = ({ width, height, isFocussed }: AnnotationsProps) => { const { annotations } = useAnnotator(); const { selectedAnnotations } = useSelectedAnnotations(); @@ -23,10 +36,12 @@ export const Annotations = ({ width, height, isFocussed }: AnnotationsProps) => ]; return ( - - {orderedAnnotations.map((annotation) => ( - - ))} - + + + {orderedAnnotations.map((annotation) => ( + + ))} + + ); }; diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index e9f816c34a..e9eb887065 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -1,8 +1,6 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { CSSProperties, MouseEvent } from 'react'; - import { Grid, View } from '@geti/ui'; import { isEmpty } from 'lodash-es'; @@ -11,38 +9,19 @@ import { ZoomTransform } from '../../components/zoom/zoom-transform'; import { useProjectIdentifier } from '../../hooks/use-project-identifier.hook'; import { getImageUrl } from '../dataset/gallery/utils'; import { Annotations } from './annotations/annotations.component'; -import { useSelectedAnnotations } from './select-annotation-provider.component'; import { ToolManager } from './tools/tool-manager.component'; import { Annotation, DatasetItem } from './types'; -const DEFAULT_ANNOTATION_STYLES = { - fillOpacity: 0.4, - fill: 'var(--annotation-fill)', - stroke: 'var(--annotation-stroke)', - strokeLinecap: 'round', - strokeWidth: 'calc(1px / var(--zoom-scale))', - strokeDashoffset: 0, - strokeDasharray: 0, - strokeOpacity: 'var(--annotation-border-opacity, 1)', -} satisfies CSSProperties; - type AnnotatorCanvasProps = { mediaItem: DatasetItem; isFocussed: boolean; }; export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) => { - const { setSelectedAnnotations } = useSelectedAnnotations(); const project_id = useProjectIdentifier(); const size = { width: mediaItem.width, height: mediaItem.height }; // todo: pass media annotations const annotations: Annotation[] = []; - const handleClickOutside = (e: MouseEvent): void => { - if (e.target === e.currentTarget) { - setSelectedAnnotations(new Set()); - } - }; - return ( @@ -52,17 +31,12 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) - + <> {!isEmpty(annotations) && ( )} - + diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 1e7767dacc..186880c85c 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -146,11 +146,7 @@ export const SegmentAnythingTool = () => { }); if (isLoading) { - return ( - - - - ); + return ; } return ( diff --git a/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx b/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx index 551aee820b..b1c1d688b2 100644 --- a/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx +++ b/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx @@ -1,10 +1,11 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { FC, PropsWithChildren, RefObject, SVGProps } from 'react'; +import { FC, MouseEvent, PropsWithChildren, RefObject, SVGProps } from 'react'; import { roiFromImage } from '@geti/smart-tools/utils'; +import { useSelectedAnnotations } from '../select-annotation-provider.component'; import { allowPanning } from '../utils'; type CanvasProps = SVGProps & { image: ImageData } & { canvasRef?: RefObject }; @@ -18,11 +19,20 @@ export const SvgToolCanvas: FC> = ({ onPointerDown, ...props }) => { + const { setSelectedAnnotations } = useSelectedAnnotations(); + const roi = roiFromImage(image); + const handleClickOutside = (e: MouseEvent): void => { + if (e.target === e.currentTarget) { + setSelectedAnnotations(new Set()); + } + }; + return ( Date: Mon, 22 Sep 2025 14:22:42 +0200 Subject: [PATCH 23/29] Minor fixes --- ui/src/assets/icons/pencil-plus copy.svg | 8 -------- ui/src/features/annotator/annotator-canvas.tsx | 17 +++++++++++++++-- ...interactive-segmentation-point.component.tsx | 4 +++- .../segment-anything-tool.component.tsx | 7 ++++--- .../tools/svg-tool-canvas.component.tsx | 12 +----------- 5 files changed, 23 insertions(+), 25 deletions(-) delete mode 100644 ui/src/assets/icons/pencil-plus copy.svg diff --git a/ui/src/assets/icons/pencil-plus copy.svg b/ui/src/assets/icons/pencil-plus copy.svg deleted file mode 100644 index ea88f630b6..0000000000 --- a/ui/src/assets/icons/pencil-plus copy.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index e9eb887065..af166f7ea2 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -1,6 +1,8 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 +import { MouseEvent } from 'react'; + import { Grid, View } from '@geti/ui'; import { isEmpty } from 'lodash-es'; @@ -9,6 +11,7 @@ import { ZoomTransform } from '../../components/zoom/zoom-transform'; import { useProjectIdentifier } from '../../hooks/use-project-identifier.hook'; import { getImageUrl } from '../dataset/gallery/utils'; import { Annotations } from './annotations/annotations.component'; +import { useSelectedAnnotations } from './select-annotation-provider.component'; import { ToolManager } from './tools/tool-manager.component'; import { Annotation, DatasetItem } from './types'; @@ -18,10 +21,18 @@ type AnnotatorCanvasProps = { }; export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) => { const project_id = useProjectIdentifier(); + const { setSelectedAnnotations } = useSelectedAnnotations(); + const size = { width: mediaItem.width, height: mediaItem.height }; // todo: pass media annotations const annotations: Annotation[] = []; + const handleClickOutside = (e: MouseEvent): void => { + if (e.target === e.currentTarget) { + setSelectedAnnotations(new Set()); + } + }; + return ( @@ -30,10 +41,12 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) Collected data - + <> {!isEmpty(annotations) && ( - + + + )} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx index 3e73ecba10..7eb95723fa 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx @@ -1,6 +1,7 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 +import { useZoom } from '../../../../components/zoom/zoom'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; interface InteractiveSegmentationPointProps extends InteractiveAnnotationPoint { @@ -8,9 +9,10 @@ interface InteractiveSegmentationPointProps extends InteractiveAnnotationPoint { } export const InteractiveSegmentationPoint = ({ x, y, positive, isLoading }: InteractiveSegmentationPointProps) => { + const { scale } = useZoom(); const fill = positive ? 'var(--brand-moss)' : 'var(--brand-coral-cobalt)'; const animationScale = `calc(1 / var(--zoom-scale))`; - const pointRadius = `calc(5 / var(--zoom-scale))`; + const pointRadius = 5 / scale; return ( <> diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 186880c85c..86b515fc2b 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -37,8 +37,9 @@ const isPositivePoint = (point: Point, shapes: Shape[], isRightClick: boolean, r // the user's cpu with too many decoding requests const THROTTLE_TIME = 150; +// TODO: Remove/move this to the secondary toolbar const toolSettings = { - interactiveMode: true, + interactiveMode: false, rightClickMode: false, }; @@ -204,7 +205,7 @@ export const SegmentAnythingTool = () => { {...SELECT_ANNOTATION_STYLES} strokeWidth={'calc(3px / var(--zoom-level))'} fillOpacity={0.0} - className={interactiveMode ? classes.stroke : classes.animateStroke} + className={classes.stroke} > { aria-label='Segment anything result' {...SELECT_ANNOTATION_STYLES} strokeWidth={'calc(3px / var(--zoom-level))'} - cursor={`url(/icons/cursor/pencil-${ + cursor={`url(/icons/pencil-${ interactiveMode === true && rightClickMode === false ? 'minus' : 'plus' }.svg) 16 16, auto`} fillOpacity={0.0} diff --git a/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx b/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx index b1c1d688b2..551aee820b 100644 --- a/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx +++ b/ui/src/features/annotator/tools/svg-tool-canvas.component.tsx @@ -1,11 +1,10 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { FC, MouseEvent, PropsWithChildren, RefObject, SVGProps } from 'react'; +import { FC, PropsWithChildren, RefObject, SVGProps } from 'react'; import { roiFromImage } from '@geti/smart-tools/utils'; -import { useSelectedAnnotations } from '../select-annotation-provider.component'; import { allowPanning } from '../utils'; type CanvasProps = SVGProps & { image: ImageData } & { canvasRef?: RefObject }; @@ -19,20 +18,11 @@ export const SvgToolCanvas: FC> = ({ onPointerDown, ...props }) => { - const { setSelectedAnnotations } = useSelectedAnnotations(); - const roi = roiFromImage(image); - const handleClickOutside = (e: MouseEvent): void => { - if (e.target === e.currentTarget) { - setSelectedAnnotations(new Set()); - } - }; - return ( Date: Mon, 22 Sep 2025 14:38:35 +0200 Subject: [PATCH 24/29] Remove duplication --- ...ment-anything-state-provider.component.tsx | 1 + .../segment-anything-tool.component.tsx | 30 ++----------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx index c237f62e60..3013d8f38b 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -102,6 +102,7 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode if (keepPreviousData) { setState((r) => ({ points: [...r.points, point] })); } else { + setState({ points: [point] }); decodingMutation.mutateAsync([point]).then(() => { setIsDrawing(false); }); diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 86b515fc2b..eddaa81c3f 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -168,36 +168,10 @@ export const SegmentAnythingTool = () => { }} > - {annotations.map((annotation, idx) => { - return ( - - - - ); - })} + <> - {showPreviewShapes && + {previewShapes.length > 0 && previewShapes.map((shape, idx) => ( Date: Mon, 22 Sep 2025 14:48:23 +0200 Subject: [PATCH 25/29] Fix loading states --- .../interactive-segmentation-point.component.tsx | 2 +- .../segment-anything-state-provider.component.tsx | 4 ++-- .../segment-anything-tool.component.tsx | 6 +++--- .../use-segment-anything.hook.ts | 12 ++++++++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx index 7eb95723fa..9eca49fa29 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx @@ -11,7 +11,7 @@ interface InteractiveSegmentationPointProps extends InteractiveAnnotationPoint { export const InteractiveSegmentationPoint = ({ x, y, positive, isLoading }: InteractiveSegmentationPointProps) => { const { scale } = useZoom(); const fill = positive ? 'var(--brand-moss)' : 'var(--brand-coral-cobalt)'; - const animationScale = `calc(1 / var(--zoom-scale))`; + const animationScale = 1 / scale; const pointRadius = 5 / scale; return ( diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx index 3013d8f38b..101f47c2d3 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx @@ -44,7 +44,7 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode const { addAnnotation } = useAnnotator(); const queryClient = useQueryClient(); - const { encodingQuery, decodingQueryFn, isLoading } = useSegmentAnythingModel(); + const { encodingQuery, decodingQueryFn, isLoading, isProcessing: isEncodingProcessing } = useSegmentAnythingModel(); const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); const decodingQueryOptions = useDecodingQueryOptions(state.points, throttledDecodingQueryFn); const decodingQuery = useDecodingQuery(state.points, throttledDecodingQueryFn); @@ -74,7 +74,7 @@ export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode return () => setIsDrawing(false); }, [setIsDrawing]); - const isProcessing = decodingQuery.isFetching; + const isProcessing = isEncodingProcessing || decodingQuery.isFetching; const hasResults = decodingQuery.data && !isEmpty(decodingQuery.data) && !isEmpty(state.points); const outputShapes = decodingQuery.data ?? []; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index eddaa81c3f..bc91122707 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -58,11 +58,11 @@ export const SegmentAnythingTool = () => { const ref = useRef(null); - const { result, points, addPoint } = useSegmentAnything(); + const { result, points, addPoint, isProcessing, isLoading } = useSegmentAnything(); const [mousePosition, setMousePosition] = useState(); const [previewShapes, setPreviewShapes] = useState([]); - const { decodingQueryFn, isLoading } = useSegmentAnything(); + const { decodingQueryFn } = useSegmentAnything(); const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); const throttleSetMousePosition = useThrottledCallback((point: InteractiveAnnotationPoint) => { @@ -219,7 +219,7 @@ export const SegmentAnythingTool = () => { x={point.x} y={point.y} positive={point.positive} - isLoading={false} + isLoading={isProcessing} /> ))} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts index bfea1cba5f..0d3c196cd1 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-segment-anything.hook.ts @@ -109,11 +109,19 @@ const useDecodingFn = (model: Remote | undefined, encoding export const useSegmentAnythingModel = () => { const encoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_ENCODER'); const decoderModel = useSegmentAnythingWorker('SEGMENT_ANYTHING_DECODER'); - const isLoading = encoderModel === undefined || decoderModel === undefined; + const isLoadingWorkers = encoderModel === undefined || decoderModel === undefined; const { mediaItem, image } = useAnnotator(); const encodingQuery = useEncodingQuery(encoderModel, mediaItem, image); const decodingQueryFn = useDecodingFn(decoderModel, encodingQuery.data); - return { isLoading, encodingQuery, decodingQueryFn }; + const isLoading = isLoadingWorkers || encodingQuery.isLoading; + const isProcessing = encodingQuery.isFetching; + + return { + isLoading, + isProcessing, + encodingQuery, + decodingQueryFn, + }; }; From ed482fa12b6aab4ecd13e6395a243b8807340594 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Mon, 22 Sep 2025 15:35:22 +0200 Subject: [PATCH 26/29] zoom-level > zoom-scale --- .../drawing-box-tool/crosshair/crosshair-line.component.tsx | 2 +- .../interactive-segmentation-point.component.tsx | 2 +- .../segment-anything-tool.component.tsx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/src/features/annotator/tools/drawing-box-tool/crosshair/crosshair-line.component.tsx b/ui/src/features/annotator/tools/drawing-box-tool/crosshair/crosshair-line.component.tsx index 20e8455703..b517055969 100644 --- a/ui/src/features/annotator/tools/drawing-box-tool/crosshair/crosshair-line.component.tsx +++ b/ui/src/features/annotator/tools/drawing-box-tool/crosshair/crosshair-line.component.tsx @@ -23,7 +23,7 @@ const colors = { }; export const CrosshairLine = ({ direction, point }: CrosshairLineProps) => { - const sizeRatio = `calc(${DEFAULT_SIZE} / var(--zoom-level))`; + const sizeRatio = `calc(${DEFAULT_SIZE} / var(--zoom-scale))`; const attributes = direction === 'horizontal' ? { diff --git a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx index 9eca49fa29..dfac98c2f6 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx @@ -24,7 +24,7 @@ export const InteractiveSegmentationPoint = ({ x, y, positive, isLoading }: Inte style={{ fill, opacity: 'var(--markers-opacity)', - strokeWidth: 'calc(1.5px / var(--zoom-level))', + strokeWidth: 'calc(1.5px / var(--zoom-scale))', stroke: 'var(--spectrum-global-color-static-gray-100)', }} data-testid={`point-${positive ? 'positive' : 'negative'}`} diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index bc91122707..0d084831da 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -47,7 +47,7 @@ const SELECT_ANNOTATION_STYLES = { fillOpacity: 0.3, fill: 'var(--energy-blue-shade)', stroke: 'var(--energy-blue-shade)', - strokeWidth: 'calc(2px / var(--zoom-level))', + strokeWidth: 'calc(2px / var(--zoom-scale))', }; export const SegmentAnythingTool = () => { @@ -177,7 +177,7 @@ export const SegmentAnythingTool = () => { key={idx} aria-label='Segment anything preview' {...SELECT_ANNOTATION_STYLES} - strokeWidth={'calc(3px / var(--zoom-level))'} + strokeWidth={'calc(3px / var(--zoom-scale))'} fillOpacity={0.0} className={classes.stroke} > @@ -196,7 +196,7 @@ export const SegmentAnythingTool = () => { key={idx} aria-label='Segment anything result' {...SELECT_ANNOTATION_STYLES} - strokeWidth={'calc(3px / var(--zoom-level))'} + strokeWidth={'calc(3px / var(--zoom-scale))'} cursor={`url(/icons/pencil-${ interactiveMode === true && rightClickMode === false ? 'minus' : 'plus' }.svg) 16 16, auto`} From 2b0fb17e5c4bf8ebbb7c31d6cf8d82f4f7033f14 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Tue, 23 Sep 2025 10:48:41 +0200 Subject: [PATCH 27/29] Remove interactiveMode files --- ui/src/assets/icons/pencil-minus.svg | 8 - .../tools/annotator-tools.component.tsx | 4 +- ...teractive-segmentation-point.component.tsx | 52 ------- ...ment-anything-state-provider.component.tsx | 139 ------------------ .../tools/tool-manager.component.tsx | 7 +- 5 files changed, 3 insertions(+), 207 deletions(-) delete mode 100644 ui/src/assets/icons/pencil-minus.svg delete mode 100644 ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx delete mode 100644 ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx diff --git a/ui/src/assets/icons/pencil-minus.svg b/ui/src/assets/icons/pencil-minus.svg deleted file mode 100644 index 4b486d6cab..0000000000 --- a/ui/src/assets/icons/pencil-minus.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/ui/src/features/annotator/tools/annotator-tools.component.tsx b/ui/src/features/annotator/tools/annotator-tools.component.tsx index 7c5b393986..ffe19ff898 100644 --- a/ui/src/features/annotator/tools/annotator-tools.component.tsx +++ b/ui/src/features/annotator/tools/annotator-tools.component.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Divider } from '@geti/ui'; -import { BoundingBox, Selector } from '@geti/ui/icons'; +import { BoundingBox, SegmentAnythingIcon, Selector } from '@geti/ui/icons'; import { ToolConfig } from '../../../components/tool-selection-bar/tools/interface'; import { Tools } from '../../../components/tool-selection-bar/tools/tools.component'; @@ -17,7 +17,7 @@ const TASK_TOOL_CONFIG: Record = { ], segmentation: [ { type: 'selection', icon: Selector }, - { type: 'sam', icon: BoundingBox }, + { type: 'sam', icon: SegmentAnythingIcon }, // TODO: Add 'polygon' tool later ], }; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx deleted file mode 100644 index dfac98c2f6..0000000000 --- a/ui/src/features/annotator/tools/segment-anything-tool/interactive-segmentation-point.component.tsx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2025 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -import { useZoom } from '../../../../components/zoom/zoom'; -import { InteractiveAnnotationPoint } from './segment-anything.interface'; - -interface InteractiveSegmentationPointProps extends InteractiveAnnotationPoint { - isLoading: boolean; -} - -export const InteractiveSegmentationPoint = ({ x, y, positive, isLoading }: InteractiveSegmentationPointProps) => { - const { scale } = useZoom(); - const fill = positive ? 'var(--brand-moss)' : 'var(--brand-coral-cobalt)'; - const animationScale = 1 / scale; - const pointRadius = 5 / scale; - - return ( - <> - - {isLoading && ( - - - - - - )} - - ); -}; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx deleted file mode 100644 index 101f47c2d3..0000000000 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-state-provider.component.tsx +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (C) 2025 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -import { createContext, ReactNode, useContext, useEffect, useState } from 'react'; - -import { EncodingOutput } from '@geti/smart-tools/segment-anything'; -import { toast } from '@geti/ui'; -import { useQueryClient, UseQueryResult } from '@tanstack/react-query'; -import { isEmpty } from 'lodash-es'; - -import { useAnnotator } from '../../annotator-provider.component'; -import { Shape } from '../../types'; -import { InteractiveAnnotationPoint } from './segment-anything.interface'; -import { useDecodingMutation, useDecodingQuery, useDecodingQueryOptions } from './use-decoding-query.hook'; -import { useSegmentAnythingModel } from './use-segment-anything.hook'; -import { useSingleStackFn } from './use-single-stack-fn.hook'; - -interface SegmentAnythingState { - points: InteractiveAnnotationPoint[]; -} - -interface SegmentAnythingStateContextProps { - isProcessing: boolean; - isLoading: boolean; - - points: InteractiveAnnotationPoint[]; - addPoint: (point: InteractiveAnnotationPoint, keepPreviousPoints?: boolean) => void; - result: { shapes: Shape[] }; - handleCancelAnnotation: () => void; - handleConfirmAnnotation: () => void; - - encodingQuery: UseQueryResult; - decodingQueryFn: (points: InteractiveAnnotationPoint[]) => Promise; -} - -const SegmentAnythingStateContext = createContext(undefined); - -export const SegmentAnythingStateProvider = ({ children }: { children: ReactNode }) => { - const [state, setState] = useState({ - points: [], - }); - const [_, setIsDrawing] = useState(false); - - const { addAnnotation } = useAnnotator(); - - const queryClient = useQueryClient(); - const { encodingQuery, decodingQueryFn, isLoading, isProcessing: isEncodingProcessing } = useSegmentAnythingModel(); - const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); - const decodingQueryOptions = useDecodingQueryOptions(state.points, throttledDecodingQueryFn); - const decodingQuery = useDecodingQuery(state.points, throttledDecodingQueryFn); - - useEffect(() => { - if (state.points.length > 0 && decodingQuery.data !== undefined && decodingQuery.data.length === 0) { - if (!decodingQuery.isPlaceholderData) { - toast({ - message: `Unable to segment object from the selected point${ - state.points.length > 1 ? 's' : '' - }. Press ESC to reset points.`, - type: 'warning', - }); - } - } - }, [decodingQuery.data, decodingQuery.isPlaceholderData, state.points]); - - const decodingMutation = useDecodingMutation(decodingQueryFn); - - const reset = async () => { - queryClient.removeQueries({ queryKey: decodingQueryOptions.queryKey }); - - setIsDrawing(false); - }; - - useEffect(() => { - return () => setIsDrawing(false); - }, [setIsDrawing]); - - const isProcessing = isEncodingProcessing || decodingQuery.isFetching; - - const hasResults = decodingQuery.data && !isEmpty(decodingQuery.data) && !isEmpty(state.points); - const outputShapes = decodingQuery.data ?? []; - const handleConfirmAnnotation = () => { - if (isProcessing) { - return; - } - - if (hasResults) { - outputShapes.map((shape) => addAnnotation(shape)); - } - - reset(); - }; - - const handleCancelAnnotation = () => { - if (!isProcessing) { - reset(); - } - }; - - const addPoint = (point: InteractiveAnnotationPoint, keepPreviousData = false) => { - setIsDrawing(true); - - if (keepPreviousData) { - setState((r) => ({ points: [...r.points, point] })); - } else { - setState({ points: [point] }); - decodingMutation.mutateAsync([point]).then(() => { - setIsDrawing(false); - }); - } - }; - - return ( - - {children} - - ); -}; - -export const useSegmentAnything = (): SegmentAnythingStateContextProps => { - const context = useContext(SegmentAnythingStateContext); - - if (context === undefined) { - throw new Error('useSegmentAnythingState must be used within a SegmentAnythingStateProvider'); - } - - return context; -}; diff --git a/ui/src/features/annotator/tools/tool-manager.component.tsx b/ui/src/features/annotator/tools/tool-manager.component.tsx index 2a3cb3269b..9af3a71cbd 100644 --- a/ui/src/features/annotator/tools/tool-manager.component.tsx +++ b/ui/src/features/annotator/tools/tool-manager.component.tsx @@ -3,7 +3,6 @@ import { useAnnotator } from '../annotator-provider.component'; import { BoundingBoxTool } from './bounding-box-tool/bounding-box-tool.component'; -import { SegmentAnythingStateProvider } from './segment-anything-tool/segment-anything-state-provider.component'; import { SegmentAnythingTool } from './segment-anything-tool/segment-anything-tool.component'; export const ToolManager = () => { @@ -12,11 +11,7 @@ export const ToolManager = () => { if (activeTool === 'bounding-box') { return ; } else if (activeTool === 'sam') { - return ( - - - - ); + return ; } return null; From 48441d5acd2101b654ee1b1f1cbe1ad61e465ffa Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Tue, 23 Sep 2025 11:05:40 +0200 Subject: [PATCH 28/29] Address comments --- .../annotations/annotations.component.tsx | 6 + .../features/annotator/annotator-canvas.tsx | 12 +- .../annotator-provider.component.tsx | 2 +- .../hooks/use-load-image-query.hook.ts | 7 +- .../bounding-box-tool.component.tsx | 4 +- .../segment-anything-tool.component.tsx | 111 +++--------------- .../use-decoding-query.hook.ts | 1 - .../media-preview/media-preview.component.tsx | 60 +++++----- 8 files changed, 67 insertions(+), 136 deletions(-) diff --git a/ui/src/features/annotator/annotations/annotations.component.tsx b/ui/src/features/annotator/annotations/annotations.component.tsx index c5f7202a65..ee60cf1766 100644 --- a/ui/src/features/annotator/annotations/annotations.component.tsx +++ b/ui/src/features/annotator/annotations/annotations.component.tsx @@ -3,6 +3,8 @@ import { CSSProperties } from 'react'; +import { isEmpty } from 'lodash-es'; + import { useAnnotator } from '../annotator-provider.component'; import { useSelectedAnnotations } from '../select-annotation-provider.component'; import { Annotation } from './annotation.component'; @@ -35,6 +37,10 @@ export const Annotations = ({ width, height, isFocussed }: AnnotationsProps) => ...annotations.filter((a) => selectedAnnotations.has(a.id)), ]; + if (isEmpty(annotations)) { + return <>; + } + return ( diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index af166f7ea2..7d3892700e 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -4,7 +4,6 @@ import { MouseEvent } from 'react'; import { Grid, View } from '@geti/ui'; -import { isEmpty } from 'lodash-es'; import { ZoomProvider } from '../../components/zoom/zoom'; import { ZoomTransform } from '../../components/zoom/zoom-transform'; @@ -24,7 +23,8 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) const { setSelectedAnnotations } = useSelectedAnnotations(); const size = { width: mediaItem.width, height: mediaItem.height }; - // todo: pass media annotations + // TODO: pass media annotations + // eslint-disable-next-line @typescript-eslint/no-unused-vars const annotations: Annotation[] = []; const handleClickOutside = (e: MouseEvent): void => { @@ -43,11 +43,9 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) <> - {!isEmpty(annotations) && ( - - - - )} + + + diff --git a/ui/src/features/annotator/annotator-provider.component.tsx b/ui/src/features/annotator/annotator-provider.component.tsx index 48812439c6..48b81fc361 100644 --- a/ui/src/features/annotator/annotator-provider.component.tsx +++ b/ui/src/features/annotator/annotator-provider.component.tsx @@ -65,7 +65,7 @@ export const AnnotatorProvider = ({ mediaItem, children }: { mediaItem: DatasetI annotations, mediaItem, - image: imageQuery.data || new ImageData(mediaItem.width, mediaItem.height), + image: imageQuery.data, roi: { x: 0, y: 0, width: mediaItem.width, height: mediaItem.height }, }} > diff --git a/ui/src/features/annotator/hooks/use-load-image-query.hook.ts b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts index cf06d8a6f4..cf8ef4d133 100644 --- a/ui/src/features/annotator/hooks/use-load-image-query.hook.ts +++ b/ui/src/features/annotator/hooks/use-load-image-query.hook.ts @@ -1,17 +1,17 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { useSuspenseQuery, UseSuspenseQueryResult } from '@tanstack/react-query'; import { API_BASE_URL } from '../../../api/client'; import { useProjectIdentifier } from '../../../hooks/use-project-identifier.hook'; import { getImageData, loadImage } from '../tools/utils'; import { DatasetItem } from '../types'; -export const useLoadImageQuery = (mediaItem: DatasetItem | undefined): UseQueryResult => { +export const useLoadImageQuery = (mediaItem: DatasetItem | undefined): UseSuspenseQueryResult => { const projectId = useProjectIdentifier(); - return useQuery({ + return useSuspenseQuery({ queryKey: ['mediaItem', mediaItem?.id, projectId], queryFn: async () => { if (mediaItem === undefined) { @@ -23,7 +23,6 @@ export const useLoadImageQuery = (mediaItem: DatasetItem | undefined): UseQueryR return getImageData(image); }, - enabled: mediaItem !== undefined && Boolean(projectId), // The image of a media item never changes so we don't want to refetch stale data staleTime: Infinity, retry: 0, diff --git a/ui/src/features/annotator/tools/bounding-box-tool/bounding-box-tool.component.tsx b/ui/src/features/annotator/tools/bounding-box-tool/bounding-box-tool.component.tsx index c90cc9a5cf..793c2e87a3 100644 --- a/ui/src/features/annotator/tools/bounding-box-tool/bounding-box-tool.component.tsx +++ b/ui/src/features/annotator/tools/bounding-box-tool/bounding-box-tool.component.tsx @@ -6,13 +6,13 @@ import { useAnnotator } from '../../annotator-provider.component'; import { DrawingBox } from '../drawing-box-tool/drawing-box.component'; export const BoundingBoxTool = () => { - const { mediaItem, addAnnotation } = useAnnotator(); + const { mediaItem, addAnnotation, image } = useAnnotator(); const { scale: zoom } = useZoom(); return ( diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 0d084831da..7c92830edd 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -3,33 +3,25 @@ import { PointerEvent, useEffect, useRef, useState } from 'react'; -import { clampPointBetweenImage, isPointInShape, pointInRectangle } from '@geti/smart-tools/utils'; +import { clampPointBetweenImage } from '@geti/smart-tools/utils'; +import { isEmpty } from 'lodash-es'; import { useZoom } from '../../../../components/zoom/zoom'; import { AnnotationShape } from '../../annotations/annotation-shape.component'; import { MaskAnnotations } from '../../annotations/mask-annotations.component'; import { useAnnotator } from '../../annotator-provider.component'; import { AnnotatorLoading } from '../../loading.component'; -import { Annotation, Point, Shape } from '../../types'; -import { isRightButton } from '../../utils'; +import { Annotation, Shape } from '../../types'; import { SvgToolCanvas } from '../svg-tool-canvas.component'; import { getRelativePoint, removeOffLimitPoints } from '../utils'; -import { InteractiveSegmentationPoint } from './interactive-segmentation-point.component'; -import { useSegmentAnything } from './segment-anything-state-provider.component'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; +import { useDecodingMutation, useDecodingQuery } from './use-decoding-query.hook'; +import { useSegmentAnythingModel } from './use-segment-anything.hook'; import { useSingleStackFn } from './use-single-stack-fn.hook'; import { useThrottledCallback } from './use-throttle-callback.hook'; import classes from './segment-anything.module.scss'; -const isPositivePoint = (point: Point, shapes: Shape[], isRightClick: boolean, rightClickMode: boolean) => { - if (rightClickMode) { - return !isRightClick; - } - - return !shapes.some((shape) => isPointInShape(shape, point)); -}; - // Whenever the user moves their mouse over the canvas we compute a preview of // SAM being applied to the user's mouse position. // The decoding step of SAM takes on average 100ms with 150-250ms being a high @@ -37,12 +29,6 @@ const isPositivePoint = (point: Point, shapes: Shape[], isRightClick: boolean, r // the user's cpu with too many decoding requests const THROTTLE_TIME = 150; -// TODO: Remove/move this to the secondary toolbar -const toolSettings = { - interactiveMode: false, - rightClickMode: false, -}; - const SELECT_ANNOTATION_STYLES = { fillOpacity: 0.3, fill: 'var(--energy-blue-shade)', @@ -51,24 +37,26 @@ const SELECT_ANNOTATION_STYLES = { }; export const SegmentAnythingTool = () => { + const [mousePosition, setMousePosition] = useState(); + const [previewShapes, setPreviewShapes] = useState([]); + const zoom = useZoom(); const { mediaItem, roi, image } = useAnnotator(); - - const clampPoint = clampPointBetweenImage(image); + const { isLoading, decodingQueryFn } = useSegmentAnythingModel(); + const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); + const decodingQuery = useDecodingQuery(mousePosition ? [mousePosition] : [], throttledDecodingQueryFn); + const decodingMutation = useDecodingMutation(decodingQueryFn); const ref = useRef(null); - const { result, points, addPoint, isProcessing, isLoading } = useSegmentAnything(); - const [mousePosition, setMousePosition] = useState(); - - const [previewShapes, setPreviewShapes] = useState([]); - const { decodingQueryFn } = useSegmentAnything(); - const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); + const clampPoint = clampPointBetweenImage(image); const throttleSetMousePosition = useThrottledCallback((point: InteractiveAnnotationPoint) => { setMousePosition(point); }, THROTTLE_TIME); + const result = decodingQuery.data ?? []; + useEffect(() => { if (mousePosition === undefined) { return; @@ -87,8 +75,6 @@ export const SegmentAnythingTool = () => { }); }, [mousePosition, throttledDecodingQueryFn, throttleSetMousePosition, roi]); - const { interactiveMode, rightClickMode } = toolSettings; - const handleMouseMove = (event: PointerEvent) => { if (!ref.current) { return; @@ -96,9 +82,7 @@ export const SegmentAnythingTool = () => { const point = clampPoint(getRelativePoint(ref.current, { x: event.clientX, y: event.clientY }, zoom.scale)); - const positive = isPositivePoint(point, result.shapes, isRightButton(event), rightClickMode); - - throttleSetMousePosition({ ...point, positive }); + throttleSetMousePosition({ ...point, positive: true }); }; const onPointerUp = (event: PointerEvent) => { @@ -110,35 +94,12 @@ export const SegmentAnythingTool = () => { return; } - if (event.pointerType === 'touch') { - return; - } - - if (!rightClickMode && isRightButton(event)) { - return; - } - - // The user must first place a positive point as otherwise we can't show a preview - if (rightClickMode && isRightButton(event) && points.length === 0) { - return; - } - const point = clampPoint(getRelativePoint(ref.current, { x: event.clientX, y: event.clientY }, zoom.scale)); - // In task chain don't allow the user to place a point outside the ROI - if (!pointInRectangle(roi, point)) { - return; - } - - const positive = isPositivePoint(point, result.shapes, isRightButton(event), rightClickMode); - - const shouldKeepPreviousPoints = interactiveMode === true || isRightButton(event); - - addPoint({ x: point.x, y: point.y, positive }, shouldKeepPreviousPoints); + decodingMutation.mutate([{ ...point, positive: true }]); }; - const showPreviewShapes = result.shapes.length === 0 && mousePosition !== undefined; - const annotations = (showPreviewShapes ? previewShapes : result.shapes).map((shape, idx): Annotation => { + const annotations = result.map((shape, idx): Annotation => { return { shape, labels: [{ id: 'id', color: 'red', name: 'Segment Anything', isPrediction: false }], @@ -162,9 +123,7 @@ export const SegmentAnythingTool = () => { setPreviewShapes([]); }} style={{ - cursor: interactiveMode - ? `url("/icons/pencil-plus.svg") 16 16, auto` - : `url("/icons/selection.svg") 8 8, auto`, + cursor: `url("/icons/selection.svg") 8 8, auto`, }} > @@ -190,38 +149,6 @@ export const SegmentAnythingTool = () => { /> ))} - - {result.shapes.map((shape, idx) => ( - - - - ))} - - {points.map((point, index) => ( - - ))} ); }; diff --git a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts index 086777a51f..c385ab5019 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts +++ b/ui/src/features/annotator/tools/segment-anything-tool/use-decoding-query.hook.ts @@ -59,7 +59,6 @@ export const useDecodingMutation = (queryFn: (points: InteractiveAnnotationPoint return removeOffLimitPoints(shape, roi); }); - // Add the shapes to the canvas here shapes.map((shape) => addAnnotation(shape)); }, }); diff --git a/ui/src/features/dataset/media-preview/media-preview.component.tsx b/ui/src/features/dataset/media-preview/media-preview.component.tsx index d10f7246ac..44033edfb3 100644 --- a/ui/src/features/dataset/media-preview/media-preview.component.tsx +++ b/ui/src/features/dataset/media-preview/media-preview.component.tsx @@ -1,7 +1,7 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { useState } from 'react'; +import { Suspense, useState } from 'react'; import { Button, ButtonGroup, Content, Dialog, Divider, Grid, Heading, ToggleButton, View } from '@geti/ui'; @@ -35,37 +35,39 @@ export const MediaPreview = ({ mediaItem, close }: MediaPreviewProps) => { columns={'100px calc(100% - 200px) 100px'} rows={'auto 1fr auto'} > - - - - + Loading...}> + + + + - - - - - + + + + + - -
Aside
- + +
Aside
+
- - - - Focus - - - - - + + + + Focus + + + + + + From 395f6ce679b83329b6925cce10cb7d4374cb88b1 Mon Sep 17 00:00:00 2001 From: Joao Vilaca Date: Tue, 23 Sep 2025 11:18:40 +0200 Subject: [PATCH 29/29] Minor fix --- ui/src/features/annotator/annotator-canvas.tsx | 8 ++++---- .../segment-anything-tool.component.tsx | 8 ++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ui/src/features/annotator/annotator-canvas.tsx b/ui/src/features/annotator/annotator-canvas.tsx index 7d3892700e..da9008c81b 100644 --- a/ui/src/features/annotator/annotator-canvas.tsx +++ b/ui/src/features/annotator/annotator-canvas.tsx @@ -1,7 +1,7 @@ // Copyright (C) 2025 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -import { MouseEvent } from 'react'; +import { PointerEvent } from 'react'; import { Grid, View } from '@geti/ui'; @@ -27,7 +27,7 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) // eslint-disable-next-line @typescript-eslint/no-unused-vars const annotations: Annotation[] = []; - const handleClickOutside = (e: MouseEvent): void => { + const handleClickOutside = (e: PointerEvent): void => { if (e.target === e.currentTarget) { setSelectedAnnotations(new Set()); } @@ -43,9 +43,9 @@ export const AnnotatorCanvas = ({ mediaItem, isFocussed }: AnnotatorCanvasProps) <> - +
- +
diff --git a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx index 7c92830edd..c34504166d 100644 --- a/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx +++ b/ui/src/features/annotator/tools/segment-anything-tool/segment-anything-tool.component.tsx @@ -4,7 +4,6 @@ import { PointerEvent, useEffect, useRef, useState } from 'react'; import { clampPointBetweenImage } from '@geti/smart-tools/utils'; -import { isEmpty } from 'lodash-es'; import { useZoom } from '../../../../components/zoom/zoom'; import { AnnotationShape } from '../../annotations/annotation-shape.component'; @@ -15,7 +14,7 @@ import { Annotation, Shape } from '../../types'; import { SvgToolCanvas } from '../svg-tool-canvas.component'; import { getRelativePoint, removeOffLimitPoints } from '../utils'; import { InteractiveAnnotationPoint } from './segment-anything.interface'; -import { useDecodingMutation, useDecodingQuery } from './use-decoding-query.hook'; +import { useDecodingMutation } from './use-decoding-query.hook'; import { useSegmentAnythingModel } from './use-segment-anything.hook'; import { useSingleStackFn } from './use-single-stack-fn.hook'; import { useThrottledCallback } from './use-throttle-callback.hook'; @@ -44,7 +43,6 @@ export const SegmentAnythingTool = () => { const { mediaItem, roi, image } = useAnnotator(); const { isLoading, decodingQueryFn } = useSegmentAnythingModel(); const throttledDecodingQueryFn = useSingleStackFn(decodingQueryFn); - const decodingQuery = useDecodingQuery(mousePosition ? [mousePosition] : [], throttledDecodingQueryFn); const decodingMutation = useDecodingMutation(decodingQueryFn); const ref = useRef(null); @@ -55,8 +53,6 @@ export const SegmentAnythingTool = () => { setMousePosition(point); }, THROTTLE_TIME); - const result = decodingQuery.data ?? []; - useEffect(() => { if (mousePosition === undefined) { return; @@ -99,7 +95,7 @@ export const SegmentAnythingTool = () => { decodingMutation.mutate([{ ...point, positive: true }]); }; - const annotations = result.map((shape, idx): Annotation => { + const annotations = previewShapes.map((shape, idx): Annotation => { return { shape, labels: [{ id: 'id', color: 'red', name: 'Segment Anything', isPrediction: false }],