diff --git a/package-lock.json b/package-lock.json index 734e529a8e..0bec6ee709 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@datadog/browser-logs": "^5.26.0", "@datadog/browser-rum": "^5.26.0", "@deepgram/sdk": "^3.6.0", - "@floating-ui/dom": "^1.6.10", + "@floating-ui/dom": "^1.6.11", "@fortawesome/fontawesome-svg-core": "1.2.36", "@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4", @@ -82,7 +82,7 @@ "kbar": "^0.1.0-beta.45", "lodash-es": "^4.17.21", "mark.js": "^8.11.1", - "marked": "^14.1.1", + "marked": "^14.1.2", "memoize-one": "^6.0.0", "mustache": "^4.2.0", "nunjucks": "^3.2.4", @@ -108,7 +108,7 @@ "react-draggable": "^4.4.6", "react-hot-toast": "^2.4.1", "react-hotkeys": "^2.0.0", - "react-image-crop": "^11.0.6", + "react-image-crop": "^11.0.7", "react-json-tree": "^0.19.0", "react-outside-click-handler": "^1.3.0", "react-redux": "^7.2.4", @@ -158,11 +158,11 @@ "devDependencies": { "@axe-core/playwright": "^4.10.0", "@fortawesome/fontawesome-common-types": "^0.2.36", - "@playwright/test": "^1.47.0", + "@playwright/test": "^1.47.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", "@shopify/jest-dom-mocks": "^5.2.0", "@sindresorhus/tsconfig": "^6.0.0", - "@sinonjs/fake-timers": "^13.0.1", + "@sinonjs/fake-timers": "^13.0.2", "@storybook/addon-actions": "^7.6.17", "@storybook/addon-essentials": "^7.6.17", "@storybook/addon-links": "^7.6.17", @@ -170,14 +170,14 @@ "@storybook/react": "^7.6.17", "@storybook/react-webpack5": "^7.6.17", "@svgr/webpack": "^8.1.0", - "@swc/core": "^1.7.24", + "@swc/core": "^1.7.26", "@swc/jest": "^0.2.36", "@testing-library/jest-dom": "^6.5.0", "@testing-library/react": "^12.1.5", "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.5.2", "@total-typescript/ts-reset": "^0.6.1", - "@types/chrome": "^0.0.270", + "@types/chrome": "^0.0.271", "@types/diff": "^5.2.2", "@types/dom-navigation": "^1.0.4", "@types/dompurify": "^3.0.5", @@ -200,7 +200,7 @@ "@types/lodash": "^4.17.7", "@types/mark.js": "^8.11.12", "@types/mustache": "^4.2.5", - "@types/node": "^22.5.4", + "@types/node": "^22.5.5", "@types/nunjucks": "^3.2.6", "@types/object-hash": "^2.1.1", "@types/papaparse": "^5.3.14", @@ -3154,12 +3154,12 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", - "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.7" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/react-dom": { @@ -3176,9 +3176,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", - "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "0.2.36", @@ -4581,12 +4581,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.0.tgz", - "integrity": "sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==", + "version": "1.47.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.1.tgz", + "integrity": "sha512-dbWpcNQZ5nj16m+A5UNScYx7HX5trIy7g4phrcitn+Nk83S32EBX/CLU4hiF4RGKX/yRc93AAqtfaXB7JWBd4Q==", "dev": true, "dependencies": { - "playwright": "1.47.0" + "playwright": "1.47.1" }, "bin": { "playwright": "cli.js" @@ -5647,9 +5647,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.1.tgz", - "integrity": "sha512-ZEbLYOvZQHccQJzbg2E5r+/Mdjb6BMdjToL4r8WwUw0VTjTnyY3gCnwLeiovcXI3/Uo25exmqmiwsjL/eE/rSg==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.2.tgz", + "integrity": "sha512-4Bb+oqXZTSTZ1q27Izly9lv8B9dlV61CROxPiVtywwzv5SnytJqhvYe6FclHYuXml4cd1VHPo1zd5PmTeJozvA==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1" @@ -7611,9 +7611,9 @@ } }, "node_modules/@swc/core": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.24.tgz", - "integrity": "sha512-FzJaai6z6DYdICAY1UKNN5pzTn296ksK2zzEjjaXlpZtoMkGktWT0ttS7hbdBCPGhLOu5Q9TA2zdPejKUFjgig==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.26.tgz", + "integrity": "sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -7628,16 +7628,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.7.24", - "@swc/core-darwin-x64": "1.7.24", - "@swc/core-linux-arm-gnueabihf": "1.7.24", - "@swc/core-linux-arm64-gnu": "1.7.24", - "@swc/core-linux-arm64-musl": "1.7.24", - "@swc/core-linux-x64-gnu": "1.7.24", - "@swc/core-linux-x64-musl": "1.7.24", - "@swc/core-win32-arm64-msvc": "1.7.24", - "@swc/core-win32-ia32-msvc": "1.7.24", - "@swc/core-win32-x64-msvc": "1.7.24" + "@swc/core-darwin-arm64": "1.7.26", + "@swc/core-darwin-x64": "1.7.26", + "@swc/core-linux-arm-gnueabihf": "1.7.26", + "@swc/core-linux-arm64-gnu": "1.7.26", + "@swc/core-linux-arm64-musl": "1.7.26", + "@swc/core-linux-x64-gnu": "1.7.26", + "@swc/core-linux-x64-musl": "1.7.26", + "@swc/core-win32-arm64-msvc": "1.7.26", + "@swc/core-win32-ia32-msvc": "1.7.26", + "@swc/core-win32-x64-msvc": "1.7.26" }, "peerDependencies": { "@swc/helpers": "*" @@ -7649,9 +7649,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.24.tgz", - "integrity": "sha512-s0k09qAcsoa8jIncwgRRd43VApYqXu28R4OmICtDffV4S01HtsRLRarXsMuLutoZk3tbxqitep+A8MPBuqNgdg==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz", + "integrity": "sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==", "cpu": [ "arm64" ], @@ -7665,9 +7665,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.24.tgz", - "integrity": "sha512-1dlsulJ/fiOoJoJyQgaCewIEaZ7Sh6aJN4r5Uhl4lIZuNWa27XOb28A3K29/6HDO9JML3IJrvXPnl5o0vxDQuQ==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz", + "integrity": "sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ==", "cpu": [ "x64" ], @@ -7681,9 +7681,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.24.tgz", - "integrity": "sha512-2ft1NmxyvHCu5CY4r2rNVybPqZtJaxpRSzvCcPlVjN/2D5Q3QgM5kBoo1t+0RCFfk4TS2V0KWJhtqKz0CNX62Q==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz", + "integrity": "sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q==", "cpu": [ "arm" ], @@ -7697,9 +7697,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.24.tgz", - "integrity": "sha512-v/Z8I9tUUNkNHKa1Sw4r1Q7Wp66ezbRhe6xMIxvPNKVJQFaMOsRpe0t8T5qbk5sV2hJGOCKpQynSpZqQXLcJDQ==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz", + "integrity": "sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==", "cpu": [ "arm64" ], @@ -7713,9 +7713,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.24.tgz", - "integrity": "sha512-0jJx0IcajcyOXaJsx1jXy86lYVrbupyy2VUj/OiJux/ic4oBJLjfL+WOuc8T8/hZj2p6X0X4jvfSCqWSuic4kA==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz", + "integrity": "sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==", "cpu": [ "arm64" ], @@ -7729,9 +7729,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.24.tgz", - "integrity": "sha512-2+3aKQpSGjVnWKDTKUPuJzitQlTQrGorg+PVFMRkv6l+RcNCHZQNe/8VYpMhyBhxDMb3LUlbp7776FRevcruxg==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz", + "integrity": "sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==", "cpu": [ "x64" ], @@ -7745,9 +7745,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.24.tgz", - "integrity": "sha512-PMQ6SkCtMoj0Ks77DiishpEmIuHpYjFLDuVOzzJCzGeGoii0yRP5lKy/VeglFYLPqJzmhK9BHlpVehVf/8ZpvA==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz", + "integrity": "sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==", "cpu": [ "x64" ], @@ -7761,9 +7761,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.24.tgz", - "integrity": "sha512-SNdCa4DtGXNWrPVHqctVUxgEVZVETuqERpqF50KFHO0Bvf5V/m1IJ4hFr2BxXlrzgnIW4t1Dpi6YOJbcGbEmnA==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz", + "integrity": "sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==", "cpu": [ "arm64" ], @@ -7777,9 +7777,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.24.tgz", - "integrity": "sha512-5p3olHqwibMfrVFg2yVuSIPh9HArDYYlJXNZ9JKqeZk23A19J1pl9MuPmXDw+sxsiPfYJ/nUedIGeUHPF/+EDw==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz", + "integrity": "sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ==", "cpu": [ "ia32" ], @@ -7793,9 +7793,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.7.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.24.tgz", - "integrity": "sha512-gRyPIxDznS8d2ClfmWbytjp2d48bij6swHnDLWhukNuOvXdQkEmaIzjEsionFG/zhcFLnz8zKfTvjEjInAMzxg==", + "version": "1.7.26", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz", + "integrity": "sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w==", "cpu": [ "x64" ], @@ -8142,9 +8142,9 @@ } }, "node_modules/@types/chrome": { - "version": "0.0.270", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.270.tgz", - "integrity": "sha512-ADvkowV7YnJfycZZxL2brluZ6STGW+9oKG37B422UePf2PCXuFA/XdERI0T18wtuWPx0tmFeZqq6MOXVk1IC+Q==", + "version": "0.0.271", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.271.tgz", + "integrity": "sha512-K0qgXvkwA5ic+/eygF1xiypHEvCoBgH5lwrhg3yva2mqJuCWyYm0vpZQ22GksAxgGfo0PWev9Zx3plp2clMlwg==", "dev": true, "dependencies": { "@types/filesystem": "*", @@ -8638,9 +8638,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.5.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", - "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", "dev": true, "dependencies": { "undici-types": "~6.19.2" @@ -21998,9 +21998,9 @@ } }, "node_modules/marked": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.1.tgz", - "integrity": "sha512-eS59oxof5eBVDCKTs+mJbvB/6Vq137GbimF9wkTIlto2/B2ppY5nigUUQgKVmA3bI2mPTIshUyDj5j612ZxlQQ==", + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.2.tgz", + "integrity": "sha512-f3r0yqpz31VXiDB/wj9GaOB0a2PRLQl6vJmXiFrniNwjkKdvakqJRULhjFKJpxOchlCRiG5fcacoUZY5Xa6PEQ==", "bin": { "marked": "bin/marked.js" }, @@ -23822,12 +23822,12 @@ } }, "node_modules/playwright": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.0.tgz", - "integrity": "sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==", + "version": "1.47.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.1.tgz", + "integrity": "sha512-SUEKi6947IqYbKxRiqnbUobVZY4bF1uu+ZnZNJX9DfU1tlf2UhWfvVjLf01pQx9URsOr18bFVUKXmanYWhbfkw==", "dev": true, "dependencies": { - "playwright-core": "1.47.0" + "playwright-core": "1.47.1" }, "bin": { "playwright": "cli.js" @@ -23840,9 +23840,9 @@ } }, "node_modules/playwright-core": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.0.tgz", - "integrity": "sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==", + "version": "1.47.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.1.tgz", + "integrity": "sha512-i1iyJdLftqtt51mEk6AhYFaAJCDx0xQ/O5NU8EKaWFgMjItPVma542Nh/Aq8aLCjIJSzjaiEQGW/nyqLkGF1OQ==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -25192,9 +25192,9 @@ } }, "node_modules/react-image-crop": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/react-image-crop/-/react-image-crop-11.0.6.tgz", - "integrity": "sha512-T+/RPBhwFxdf8PjD/uoWk+tBkS0Xf2XW0lY5mnsmClvnAujO81EEjDwj0M2pcHX3seXVgKOr/yIiL+Sx4evMNw==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/react-image-crop/-/react-image-crop-11.0.7.tgz", + "integrity": "sha512-ZciKWHDYzmm366JDL18CbrVyjnjH0ojufGDmScfS4ZUqLHg4nm6ATY+K62C75W4ZRNt4Ii+tX0bSjNk9LQ2xzQ==", "peerDependencies": { "react": ">=16.13.1" } diff --git a/package.json b/package.json index 984b015e99..e7fafdd21a 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@datadog/browser-logs": "^5.26.0", "@datadog/browser-rum": "^5.26.0", "@deepgram/sdk": "^3.6.0", - "@floating-ui/dom": "^1.6.10", + "@floating-ui/dom": "^1.6.11", "@fortawesome/fontawesome-svg-core": "1.2.36", "@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4", @@ -107,7 +107,7 @@ "kbar": "^0.1.0-beta.45", "lodash-es": "^4.17.21", "mark.js": "^8.11.1", - "marked": "^14.1.1", + "marked": "^14.1.2", "memoize-one": "^6.0.0", "mustache": "^4.2.0", "nunjucks": "^3.2.4", @@ -133,7 +133,7 @@ "react-draggable": "^4.4.6", "react-hot-toast": "^2.4.1", "react-hotkeys": "^2.0.0", - "react-image-crop": "^11.0.6", + "react-image-crop": "^11.0.7", "react-json-tree": "^0.19.0", "react-outside-click-handler": "^1.3.0", "react-redux": "^7.2.4", @@ -183,11 +183,11 @@ "devDependencies": { "@axe-core/playwright": "^4.10.0", "@fortawesome/fontawesome-common-types": "^0.2.36", - "@playwright/test": "^1.47.0", + "@playwright/test": "^1.47.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", "@shopify/jest-dom-mocks": "^5.2.0", "@sindresorhus/tsconfig": "^6.0.0", - "@sinonjs/fake-timers": "^13.0.1", + "@sinonjs/fake-timers": "^13.0.2", "@storybook/addon-actions": "^7.6.17", "@storybook/addon-essentials": "^7.6.17", "@storybook/addon-links": "^7.6.17", @@ -195,14 +195,14 @@ "@storybook/react": "^7.6.17", "@storybook/react-webpack5": "^7.6.17", "@svgr/webpack": "^8.1.0", - "@swc/core": "^1.7.24", + "@swc/core": "^1.7.26", "@swc/jest": "^0.2.36", "@testing-library/jest-dom": "^6.5.0", "@testing-library/react": "^12.1.5", "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.5.2", "@total-typescript/ts-reset": "^0.6.1", - "@types/chrome": "^0.0.270", + "@types/chrome": "^0.0.271", "@types/diff": "^5.2.2", "@types/dom-navigation": "^1.0.4", "@types/dompurify": "^3.0.5", @@ -225,7 +225,7 @@ "@types/lodash": "^4.17.7", "@types/mark.js": "^8.11.12", "@types/mustache": "^4.2.5", - "@types/node": "^22.5.4", + "@types/node": "^22.5.5", "@types/nunjucks": "^3.2.6", "@types/object-hash": "^2.1.1", "@types/papaparse": "^5.3.14", diff --git a/src/activation/useActivateMod.test.ts b/src/activation/useActivateMod.test.ts index 754c961697..124bd36313 100644 --- a/src/activation/useActivateMod.test.ts +++ b/src/activation/useActivateMod.test.ts @@ -18,7 +18,7 @@ import { type WizardValues } from "@/activation/wizardTypes"; import { renderHook } from "@/pageEditor/testHelpers"; import useActivateMod from "./useActivateMod"; -import { validateRegistryId } from "@/types/helpers"; +import { uuidv4, validateRegistryId } from "@/types/helpers"; import { type StarterBrickDefinitionLike } from "@/starterBricks/types"; import { type ContextMenuDefinition } from "@/starterBricks/contextMenu/contextMenuTypes"; import { deactivateMod } from "@/store/deactivateUtils"; @@ -41,8 +41,17 @@ import { appApiMock } from "@/testUtils/appApiMock"; import type MockAdapter from "axios-mock-adapter"; import { StarterBrickTypes } from "@/types/starterBrickTypes"; import { API_PATHS } from "@/data/service/urlPaths"; +import { waitForEffect } from "@/testUtils/testHelpers"; +import { editablePackageMetadataFactory } from "@/testUtils/factories/registryFactories"; +import notify from "@/utils/notify"; +import { + type Deployment, + type EditablePackageMetadata, +} from "@/types/contract"; jest.mock("@/contentScript/messenger/api"); +jest.mock("@/utils/notify"); +const mockedNotifyError = jest.mocked(notify.error); const checkPermissionsMock = jest.mocked(checkModDefinitionPermissions); const deactivateModMock = jest.mocked(deactivateMod); @@ -109,6 +118,7 @@ function setUserAcceptedPermissions(accepted: boolean) { describe("useActivateMod", () => { beforeEach(() => { reactivateEveryTabMock.mockClear(); + appApiMock.reset(); }); it("returns error if permissions are not granted", async () => { @@ -332,4 +342,193 @@ describe("useActivateMod", () => { expect(success).toBe(false); expect(error).toBe(errorMessage); }); + + describe("personal deployment functionality", () => { + const packageVersionId = "package-version-id"; + const testDeployment = { + id: uuidv4(), + name: "test-user-deployment", + } as Deployment; + let formValues: WizardValues; + let editablePackage: EditablePackageMetadata; + let modDefinition: ModDefinition; + + beforeEach(() => { + ({ formValues, modDefinition } = setupInputs()); + + setModHasPermissions(true); + setUserAcceptedPermissions(true); + + editablePackage = editablePackageMetadataFactory({ + name: modDefinition.metadata.id, + }); + }); + + it("handles personal deployment creation successfully", async () => { + appApiMock.onGet(API_PATHS.BRICKS).reply(200, [editablePackage]); + appApiMock + .onGet(API_PATHS.BRICK_VERSIONS(editablePackage.id)) + .reply(200, [ + { id: packageVersionId, version: modDefinition.metadata.version }, + ]); + appApiMock.onPost(API_PATHS.USER_DEPLOYMENTS).reply(201, testDeployment); + + const { result, getReduxStore } = renderHook( + () => useActivateMod("marketplace"), + { + setupRedux(_dispatch, { store }) { + jest.spyOn(store, "dispatch"); + }, + }, + ); + + const { success, error } = await result.current( + { ...formValues, personalDeployment: true }, + modDefinition, + ); + + expect(success).toBe(true); + expect(error).toBeUndefined(); + + const { dispatch } = getReduxStore(); + + expect(dispatch).toHaveBeenCalledWith( + modComponentSlice.actions.activateMod({ + modDefinition, + configuredDependencies: [], + optionsArgs: formValues.optionsArgs, + screen: "marketplace", + isReactivate: false, + deployment: testDeployment, + }), + ); + + expect( + JSON.parse( + appApiMock.history.post!.find( + (request) => request.url === API_PATHS.USER_DEPLOYMENTS, + )!.data, + ), + ).toEqual({ + package_version: packageVersionId, + name: `Personal deployment for ${modDefinition.metadata.name}, version ${modDefinition.metadata.version}`, + services: [], + options_config: formValues.optionsArgs, + }); + }); + + it("notifies error when personal deployment was not created due to missing package", async () => { + appApiMock.onGet(API_PATHS.BRICKS).reply(200, []); + + const { result } = renderHook(() => useActivateMod("marketplace")); + await waitForEffect(); + + const { success, error } = await result.current( + { ...formValues, personalDeployment: true }, + modDefinition, + ); + + expect(success).toBe(true); + expect(error).toBeUndefined(); + + expect(mockedNotifyError).toHaveBeenCalledWith({ + message: `Error setting up device synchronization for ${modDefinition.metadata.name}. Please try reactivating.`, + error: new Error( + `Failed to find editable package for mod: ${modDefinition.metadata.id}`, + ), + }); + }); + + it("notifies error when personal deployment was not created due to failed package call", async () => { + appApiMock.onGet(API_PATHS.BRICKS).reply(500); + + const { result } = renderHook(() => useActivateMod("marketplace")); + + const { success, error } = await result.current( + { ...formValues, personalDeployment: true }, + modDefinition, + ); + + expect(success).toBe(true); + expect(error).toBeUndefined(); + + expect(mockedNotifyError).toHaveBeenCalledWith({ + message: `Error setting up device synchronization for ${modDefinition.metadata.name}. Please try reactivating.`, + error: expect.objectContaining({ + message: "Request failed with status code 500", + }), + }); + }); + + it("notifies error when personal deployment was not created due to missing package version", async () => { + appApiMock.onGet(API_PATHS.BRICKS).reply(200, [editablePackage]); + appApiMock + .onGet(API_PATHS.BRICK_VERSIONS(editablePackage.id)) + .reply(200, []); + + const { result } = renderHook(() => useActivateMod("marketplace")); + + const { success, error } = await result.current( + { ...formValues, personalDeployment: true }, + modDefinition, + ); + + expect(success).toBe(true); + expect(error).toBeUndefined(); + + expect(mockedNotifyError).toHaveBeenCalledWith({ + message: `Error setting up device synchronization for ${modDefinition.metadata.name}. Please try reactivating.`, + error: new Error("Failed to find package version: 1.0.0"), + }); + }); + + it("notifies error when personal deployment was not created due to failed package versions call", async () => { + appApiMock.onGet(API_PATHS.BRICKS).reply(200, [editablePackage]); + appApiMock.onGet(API_PATHS.BRICK_VERSIONS(editablePackage.id)).reply(500); + + const { result } = renderHook(() => useActivateMod("marketplace")); + + const { success, error } = await result.current( + { ...formValues, personalDeployment: true }, + modDefinition, + ); + + expect(success).toBe(true); + expect(error).toBeUndefined(); + + expect(mockedNotifyError).toHaveBeenCalledWith({ + message: `Error setting up device synchronization for ${modDefinition.metadata.name}. Please try reactivating.`, + error: expect.objectContaining({ + message: "Request failed with status code 500", + }), + }); + }); + + it("notifies error when personal deployment was not created due to failed deployment call", async () => { + appApiMock.onGet(API_PATHS.BRICKS).reply(200, [editablePackage]); + appApiMock + .onGet(API_PATHS.BRICK_VERSIONS(editablePackage.id)) + .reply(200, [ + { id: packageVersionId, version: modDefinition.metadata.version }, + ]); + appApiMock.onPost(API_PATHS.USER_DEPLOYMENTS).reply(500); + + const { result } = renderHook(() => useActivateMod("marketplace")); + + const { success, error } = await result.current( + { ...formValues, personalDeployment: true }, + modDefinition, + ); + + expect(success).toBe(true); + expect(error).toBeUndefined(); + + expect(mockedNotifyError).toHaveBeenCalledWith({ + message: `Error setting up device synchronization for ${modDefinition.metadata.name}. Please try reactivating.`, + error: expect.objectContaining({ + message: "Request failed with status code 500", + }), + }); + }); + }); }); diff --git a/src/activation/useActivateMod.ts b/src/activation/useActivateMod.ts index d02cbdba47..ac145d2389 100644 --- a/src/activation/useActivateMod.ts +++ b/src/activation/useActivateMod.ts @@ -26,11 +26,17 @@ import { deactivateMod } from "@/store/deactivateUtils"; import { selectActivatedModComponents } from "@/store/modComponents/modComponentSelectors"; import { ensurePermissionsFromUserGesture } from "@/permissions/permissionsUtils"; import { checkModDefinitionPermissions } from "@/modDefinitions/modDefinitionPermissionsHelpers"; -import { useCreateDatabaseMutation } from "@/data/service/api"; +import { + useCreateDatabaseMutation, + useCreateUserDeploymentMutation, +} from "@/data/service/api"; import { Events } from "@/telemetry/events"; import { reloadModsEveryTab } from "@/contentScript/messenger/api"; import { autoCreateDatabaseOptionsArgsInPlace } from "@/activation/modOptionsHelpers"; import { type ReportEventData } from "@/telemetry/telemetryTypes"; +import { type Deployment, type DeploymentPayload } from "@/types/contract"; +import { PIXIEBRIX_INTEGRATION_ID } from "@/integrations/constants"; +import notify from "@/utils/notify"; export type ActivateResult = { success: boolean; @@ -78,12 +84,14 @@ function useActivateMod( const activatedModComponents = useSelector(selectActivatedModComponents); const [createDatabase] = useCreateDatabaseMutation(); + const [createUserDeployment] = useCreateUserDeploymentMutation(); return useCallback( async (formValues: WizardValues, modDefinition: ModDefinition) => { - const isReactivate = activatedModComponents.some( + const activeModComponent = activatedModComponents.find( (x) => x._recipe?.id === modDefinition.metadata.id, ); + const isReactivate = Boolean(activeModComponent); if (source === "extensionConsole") { // Note: The prefix "Marketplace" on the telemetry event name @@ -152,6 +160,42 @@ function useActivateMod( dispatch, ); + // TODO: handle updating a deployment from a previous version to the new version and + // handle deleting a deployment if the user turns off personal deployment + // https://github.com/pixiebrix/pixiebrix-extension/issues/9092 + let createdUserDeployment: Deployment | undefined; + if ( + formValues.personalDeployment && + // Avoid creating a personal deployment if the mod already has one + !activeModComponent?._deployment?.isPersonalDeployment + ) { + const data: DeploymentPayload = { + name: `Personal deployment for ${modDefinition.metadata.name}, version ${modDefinition.metadata.version}`, + services: integrationDependencies.flatMap( + (integrationDependency) => + integrationDependency.integrationId === + PIXIEBRIX_INTEGRATION_ID || + integrationDependency.configId == null + ? [] + : [{ auth: integrationDependency.configId }], + ), + options_config: optionsArgs, + }; + const result = await createUserDeployment({ + modDefinition, + data, + }); + + if ("error" in result) { + notify.error({ + message: `Error setting up device synchronization for ${modDefinition.metadata.name}. Please try reactivating.`, + error: result.error, + }); + } else { + createdUserDeployment = result.data; + } + } + dispatch( modComponentSlice.actions.activateMod({ modDefinition, @@ -159,6 +203,7 @@ function useActivateMod( optionsArgs, screen: source, isReactivate: existingModComponents.length > 0, + deployment: createdUserDeployment, }), ); @@ -170,12 +215,10 @@ function useActivateMod( error, }); - if (typeof errorMessage === "string") { - return { - success: false, - error: errorMessage, - }; - } + return { + success: false, + error: errorMessage, + }; } return { @@ -183,11 +226,12 @@ function useActivateMod( }; }, [ - createDatabase, - dispatch, activatedModComponents, source, checkPermissions, + dispatch, + createDatabase, + createUserDeployment, ], ); } diff --git a/src/activation/useActivateModWizard.ts b/src/activation/useActivateModWizard.ts index 7ad281b7cc..1bad7e10d4 100644 --- a/src/activation/useActivateModWizard.ts +++ b/src/activation/useActivateModWizard.ts @@ -118,6 +118,10 @@ export function wizardStateFactory({ ({ integrationId, configId }) => [integrationId, configId], ), ); + const hasPersonalDeployment = activatedModComponentsForMod?.some( + (x) => x._deployment?.isPersonalDeployment, + ); + const unconfiguredIntegrationDependencies = getUnconfiguredComponentIntegrations(modDefinition); const integrationDependencies = unconfiguredIntegrationDependencies.map( @@ -188,7 +192,7 @@ export function wizardStateFactory({ return forcePrimitive(optionSchema.default); }, ), - personalDeployment: false, + personalDeployment: hasPersonalDeployment, }; const validationSchema = Yup.object().shape({ diff --git a/src/components/AsyncButton.tsx b/src/components/AsyncButton.tsx index 7c30d0ba5b..07f6044a9c 100644 --- a/src/components/AsyncButton.tsx +++ b/src/components/AsyncButton.tsx @@ -31,51 +31,59 @@ export type AsyncButtonProps = ButtonProps & { ariaLabel?: string; }; -const AsyncButton: React.FunctionComponent = ({ - ariaLabel, - onClick, - children, - disabled: manualDisabled = false, - ...buttonProps -}) => { - const mounted = useRef(false); - const [pending, setPending] = useState(false); +const AsyncButton = React.forwardRef( + ( + { + ariaLabel, + onClick, + children, + disabled: manualDisabled = false, + ...buttonProps + }, + ref, + ) => { + const mounted = useRef(false); + const [pending, setPending] = useState(false); - useEffect(() => { - // https://stackoverflow.com/a/66555159/402560 - mounted.current = true; - return () => { - mounted.current = false; - }; - }, []); + useEffect(() => { + // https://stackoverflow.com/a/66555159/402560 + mounted.current = true; + return () => { + mounted.current = false; + }; + }, []); - const handleClick = useCallback( - async (event: React.MouseEvent) => { - setPending(true); - try { - await onClick(event); - } finally { - if (mounted.current) { - setPending(false); + const handleClick = useCallback( + async (event: React.MouseEvent) => { + setPending(true); + try { + await onClick(event); + } finally { + if (mounted.current) { + setPending(false); + } } - } - }, - [onClick], - ); + }, + [onClick], + ); - return ( - - ); -}; + return ( + + ); + }, +); + +AsyncButton.displayName = "AsyncButton"; export default AsyncButton; diff --git a/src/data/service/api.ts b/src/data/service/api.ts index e66a5a02a0..66196bed33 100644 --- a/src/data/service/api.ts +++ b/src/data/service/api.ts @@ -31,6 +31,7 @@ import { type PendingInvitation, type RetrieveRecipeResponse, type RemoteIntegrationConfig, + type DeploymentPayload, } from "@/types/contract"; import { type components } from "@/types/swagger"; import { dumpBrickYaml } from "@/runtime/brickYaml"; @@ -351,14 +352,21 @@ export const appApi = createApi({ }), listPackageVersions: builder.query< PackageVersionDeprecated[], - { id: UUID } + { packageId: UUID } >({ - query: ({ id }) => ({ - url: API_PATHS.BRICK_VERSIONS(id), + query: ({ packageId }) => ({ + url: API_PATHS.BRICK_VERSIONS(packageId), method: "get", }), - providesTags: (result, error, { id }) => [ - { type: "PackageVersion", id: `PACKAGE-${id}-LIST` }, + providesTags: (result, error, { packageId }) => [ + { type: "Package", id: packageId }, + { type: "PackageVersion", id: `PACKAGE-${packageId}-LIST` }, + ...(result + ? result.map((x) => ({ + type: "PackageVersion" as const, + id: x.id, + })) + : []), ], }), updateScope: builder.mutation< @@ -402,6 +410,88 @@ export const appApi = createApi({ }), providesTags: ["Deployments"], }), + createUserDeployment: builder.mutation< + Deployment, + { + modDefinition: ModDefinition; + data: Exclude; + } + >({ + async queryFn( + { modDefinition, data }, + { dispatch }, + _, + baseQuery, + ): Promise< + | { + data: Deployment; + } + | { error: unknown } + > { + const { + data: editablePackages, + error: editablePackagesError, + isError: isEditablePackagesError, + } = await dispatch(appApi.endpoints.getEditablePackages.initiate()); + + if (isEditablePackagesError) { + return { error: editablePackagesError }; + } + + const packageId = editablePackages?.find( + (x) => x.name === modDefinition.metadata.id, + )?.id; + + if (!packageId) { + return { + error: new Error( + `Failed to find editable package for mod: ${modDefinition.metadata.id}`, + ), + }; + } + + const { + data: packageVersions = [], + error: packageVersionsError, + isError: isPackageVersionsError, + } = await dispatch( + appApi.endpoints.listPackageVersions.initiate({ + packageId, + }), + ); + + if (isPackageVersionsError) { + return { error: packageVersionsError }; + } + + const packageVersion = packageVersions.find( + (modVersion) => modVersion.version === modDefinition.metadata.version, + ); + + if (!packageVersion) { + return { + error: new Error( + `Failed to find package version: ${modDefinition.metadata.version}`, + ), + }; + } + + const createDeploymentResult = await baseQuery({ + url: API_PATHS.USER_DEPLOYMENTS, + method: "post", + data: { + ...data, + package_version: packageVersion.id, + }, + }); + + return { + ...createDeploymentResult, + data: createDeploymentResult.data as Deployment, + }; + }, + invalidatesTags: ["Deployments"], + }), }), }); @@ -431,5 +521,6 @@ export const { useGetStarterBlueprintsQuery, useCreateMilestoneMutation, useGetDeploymentsQuery, + useCreateUserDeploymentMutation, util, } = appApi; diff --git a/src/data/service/urlPaths.ts b/src/data/service/urlPaths.ts index 50d195de36..d7ec1836b5 100644 --- a/src/data/service/urlPaths.ts +++ b/src/data/service/urlPaths.ts @@ -16,6 +16,7 @@ */ import type { RegistryId } from "@/types/registryTypes"; +import { type paths } from "@/types/swagger"; export const API_PATHS = { BRICKS: "/api/bricks/", @@ -34,6 +35,8 @@ export const API_PATHS = { DEPLOYMENT_ALERTS: (deploymentId: string) => `/api/deployments/${deploymentId}/alerts/`, + USER_DEPLOYMENTS: "/api/me/deployments/" satisfies keyof paths, + FEATURE_FLAGS: "/api/me/", GROUP_DATABASES: (groupId: string) => `/api/groups/${groupId}/databases/`, diff --git a/src/extensionConsole/pages/packageEditor/PackageHistory.tsx b/src/extensionConsole/pages/packageEditor/PackageHistory.tsx index 3a8ac043b6..2d51b841ab 100644 --- a/src/extensionConsole/pages/packageEditor/PackageHistory.tsx +++ b/src/extensionConsole/pages/packageEditor/PackageHistory.tsx @@ -69,7 +69,7 @@ const PackageHistory: React.FunctionComponent<{ }> = ({ packageId }) => { const { data: editablePackage } = useGetPackageQuery({ id: packageId }); const { data: packageVersions } = useListPackageVersionsQuery({ - id: packageId, + packageId, }); const versionOptions = useMemo( diff --git a/src/types/contract.ts b/src/types/contract.ts index da374831f7..fd43786178 100644 --- a/src/types/contract.ts +++ b/src/types/contract.ts @@ -109,6 +109,10 @@ export type Deployment = components["schemas"]["DeploymentDetail"] & { }; }; +export type DeploymentPayload = Partial & { + includeDependencies?: boolean; +}; + /** * Metadata for an editable package in the registry. See PackageMetaSerializer. */