diff --git a/package-lock.json b/package-lock.json index d2dc5cbb1..7ed606991 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@azure/cosmos": "4.7.0", "@azure/cosmos-language-service": "0.0.5", "@azure/identity": "4.5.0", - "@azure/msal-browser": "^5.2.0", + "@azure/msal-browser": "^5.4.0", "@babel/plugin-proposal-class-properties": "7.12.1", "@babel/plugin-proposal-decorators": "7.12.12", "@fluentui/react": "8.119.0", @@ -130,7 +130,7 @@ "@babel/preset-env": "7.24.7", "@babel/preset-react": "7.24.7", "@babel/preset-typescript": "7.24.7", - "@playwright/test": "1.55.1", + "@playwright/test": "1.59.1", "@testing-library/react": "11.2.3", "@types/applicationinsights-js": "1.0.7", "@types/codemirror": "0.0.56", @@ -7099,19 +7099,23 @@ } }, "node_modules/@nteract/data-explorer/node_modules/react-dom": { - "version": "18.2.0", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/@nteract/data-explorer/node_modules/scheduler": { - "version": "0.23.0", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", "peer": true, "dependencies": { @@ -7649,24 +7653,17 @@ "react-redux": "^7.2.0" } }, - "node_modules/@nteract/mythic-configuration/node_modules/@types/react-redux": { - "version": "7.1.31", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, "node_modules/@nteract/mythic-configuration/node_modules/react-is": { "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "license": "MIT", "peer": true }, "node_modules/@nteract/mythic-configuration/node_modules/react-redux": { "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", "license": "MIT", "peer": true, "dependencies": { @@ -7718,24 +7715,17 @@ "react-redux": "^7.2.0" } }, - "node_modules/@nteract/mythic-notifications/node_modules/@types/react-redux": { - "version": "7.1.31", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, "node_modules/@nteract/mythic-notifications/node_modules/react-is": { "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "license": "MIT", "peer": true }, "node_modules/@nteract/mythic-notifications/node_modules/react-redux": { "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", "license": "MIT", "peer": true, "dependencies": { @@ -7987,6 +7977,8 @@ }, "node_modules/@octokit/auth-token": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", "license": "MIT", "peer": true, "engines": { @@ -7994,15 +7986,17 @@ } }, "node_modules/@octokit/core": { - "version": "5.0.2", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", + "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", "license": "MIT", "peer": true, "dependencies": { "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.0.0", - "@octokit/request": "^8.0.2", - "@octokit/request-error": "^5.0.0", - "@octokit/types": "^12.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.4.1", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" }, @@ -8010,6 +8004,23 @@ "node": ">= 18" } }, + "node_modules/@octokit/core/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT", + "peer": true + }, + "node_modules/@octokit/core/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, "node_modules/@octokit/endpoint": { "version": "9.0.6", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", @@ -8036,18 +8047,37 @@ } }, "node_modules/@octokit/graphql": { - "version": "7.0.2", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", "license": "MIT", "peer": true, "dependencies": { - "@octokit/request": "^8.0.1", - "@octokit/types": "^12.0.0", + "@octokit/request": "^8.4.1", + "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" }, "engines": { "node": ">= 18" } }, + "node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT", + "peer": true + }, + "node_modules/@octokit/graphql/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, "node_modules/@octokit/openapi-types": { "version": "20.0.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", @@ -8160,6 +8190,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.0.3" } @@ -8168,6 +8199,7 @@ "version": "6.41.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", + "license": "MIT", "dependencies": { "@octokit/openapi-types": "^12.11.0" } @@ -8176,6 +8208,7 @@ "version": "2.5.4", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.5.4.tgz", "integrity": "sha512-HCp8yKQfTITYK+Nd09MHzAlP1v3Ii/oCohv0/TW9rhSLvzb98BOVs2QmVYuloE6a3l6LsfyGIwb6Pc4ycgWlIQ==", + "license": "MIT", "dependencies": { "@octokit/auth-token": "^2.4.0", "@octokit/graphql": "^4.3.1", @@ -8189,6 +8222,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", + "license": "ISC", "dependencies": { "os-name": "^3.1.0" } @@ -8197,6 +8231,7 @@ "version": "4.8.0", "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "license": "MIT", "dependencies": { "@octokit/request": "^5.6.0", "@octokit/types": "^6.0.3", @@ -8207,6 +8242,7 @@ "version": "6.41.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", + "license": "MIT", "dependencies": { "@octokit/openapi-types": "^12.11.0" } @@ -8214,12 +8250,14 @@ "node_modules/@octokit/rest/node_modules/@octokit/openapi-types": { "version": "12.11.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", - "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==", + "license": "MIT" }, "node_modules/@octokit/rest/node_modules/@octokit/types": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", + "license": "MIT", "dependencies": { "@types/node": ">= 8" } @@ -8547,12 +8585,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", - "integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", + "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", "dev": true, "dependencies": { - "playwright": "1.55.1" + "playwright": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -9785,7 +9823,6 @@ }, "node_modules/@types/react-redux": { "version": "7.1.7", - "dev": true, "license": "MIT", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", @@ -12731,6 +12768,9 @@ }, "node_modules/crypto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.", "license": "ISC", "peer": true }, @@ -22340,21 +22380,13 @@ "dependencies": { "camelcase": "^3.0.0", "less-vars-to-js": "^1.1.2", - "loader-utils": "^0.2.16", + "loader-utils": "1.4.2", "object.entries": "^1.0.3" }, "engines": { "node": ">=5" } }, - "node_modules/less-vars-loader/node_modules/big.js": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/less-vars-loader/node_modules/camelcase": { "version": "3.0.0", "dev": true, @@ -22363,37 +22395,6 @@ "node": ">=0.10.0" } }, - "node_modules/less-vars-loader/node_modules/emojis-list": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/less-vars-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/less-vars-loader/node_modules/loader-utils": { - "version": "0.2.17", - "dev": true, - "license": "MIT", - "dependencies": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - }, "node_modules/less-vars-to-js": { "version": "1.3.0", "dev": true, @@ -22663,6 +22664,7 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", + "license": "MIT", "engines": { "node": ">=6" }, @@ -23438,6 +23440,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "license": "MIT", "dependencies": { "macos-release": "^2.2.0", "windows-release": "^3.1.0" @@ -23450,6 +23453,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", "engines": { "node": ">=4" } @@ -23949,12 +23953,12 @@ "dev": true }, "node_modules/playwright": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", - "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", + "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", "dev": true, "dependencies": { - "playwright-core": "1.55.1" + "playwright-core": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -23967,9 +23971,9 @@ } }, "node_modules/playwright-core": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", - "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -26773,6 +26777,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -29396,6 +29401,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz", "integrity": "sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==", + "license": "MIT", "dependencies": { "execa": "^1.0.0" }, @@ -29410,6 +29416,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "license": "MIT", "dependencies": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", @@ -29427,6 +29434,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -29438,6 +29446,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -29446,6 +29455,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "license": "MIT", "dependencies": { "path-key": "^2.0.0" }, @@ -29457,6 +29467,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "license": "MIT", "engines": { "node": ">=4" } diff --git a/package.json b/package.json index 5e71c1b74..116612d6a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "@azure/cosmos": "4.7.0", "@azure/cosmos-language-service": "0.0.5", "@azure/identity": "4.5.0", - "@azure/msal-browser": "^5.2.0", + "@azure/msal-browser": "^5.4.0", "@babel/plugin-proposal-class-properties": "7.12.1", "@babel/plugin-proposal-decorators": "7.12.12", "@fluentui/react": "8.119.0", @@ -124,21 +124,23 @@ "d3-color": "3.1.0", "cross-spawn": "7.0.6", "less-vars-loader": { - "json5": "1.0.2" + "json5": "1.0.2", + "loader-utils": "1.4.2" }, "trim": "0.0.3", "@octokit/plugin-paginate-rest": "9.2.2", "@octokit/request-error": "5.1.1", "@octokit/request": "8.4.1", "prismjs": "1.30.0", - "sanitize-html": "2.17.0" + "sanitize-html": "2.17.0", + "@types/react-redux": "7.1.7" }, "devDependencies": { "@babel/core": "7.29.0", "@babel/preset-env": "7.24.7", "@babel/preset-react": "7.24.7", "@babel/preset-typescript": "7.24.7", - "@playwright/test": "1.55.1", + "@playwright/test": "1.59.1", "@testing-library/react": "11.2.3", "@types/applicationinsights-js": "1.0.7", "@types/codemirror": "0.0.56", diff --git a/patches/less-vars-loader+1.1.0.patch b/patches/less-vars-loader+1.1.0.patch new file mode 100644 index 000000000..43750bf86 --- /dev/null +++ b/patches/less-vars-loader+1.1.0.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/less-vars-loader/index.js b/node_modules/less-vars-loader/index.js +index 14183c1..095c807 100644 +--- a/node_modules/less-vars-loader/index.js ++++ b/node_modules/less-vars-loader/index.js +@@ -7,7 +7,7 @@ const entries = require('object.entries'); + + module.exports = function(source) { + this.cacheable && this.cacheable(); +- const query = loaderUtils.parseQuery(this.query); ++ const query = loaderUtils.getOptions(this) || {}; + const camelCaseKeys = !!(query.camelCase || query.camelcase); + const resolveVariables = !!(query.resolveVariables || query.resolvevariables); + diff --git a/src/Contracts/DataModels.ts b/src/Contracts/DataModels.ts index ab179f0ee..0a51d721a 100644 --- a/src/Contracts/DataModels.ts +++ b/src/Contracts/DataModels.ts @@ -347,6 +347,7 @@ export interface Offer { export interface ThroughputBucket { id: number; maxThroughputPercentage: number; + isDefaultBucket?: boolean; } export interface SDKOfferDefinition extends Resource { diff --git a/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.test.tsx b/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.test.tsx index 2ad5c819e..08bc60e40 100644 --- a/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.test.tsx +++ b/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.test.tsx @@ -76,11 +76,11 @@ describe("ThroughputBucketsComponent", () => { fireEvent.change(input, { target: { value: "70" } }); expect(mockOnBucketsChange).toHaveBeenCalledWith([ - { id: 1, maxThroughputPercentage: 70 }, - { id: 2, maxThroughputPercentage: 60 }, - { id: 3, maxThroughputPercentage: 100 }, - { id: 4, maxThroughputPercentage: 100 }, - { id: 5, maxThroughputPercentage: 100 }, + { id: 1, maxThroughputPercentage: 70, isDefaultBucket: false }, + { id: 2, maxThroughputPercentage: 60, isDefaultBucket: false }, + { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false }, ]); }); @@ -102,11 +102,11 @@ describe("ThroughputBucketsComponent", () => { fireEvent.change(input2, { target: { value: "80" } }); expect(mockOnBucketsChange).toHaveBeenCalledWith([ - { id: 1, maxThroughputPercentage: 70 }, - { id: 2, maxThroughputPercentage: 80 }, - { id: 3, maxThroughputPercentage: 100 }, - { id: 4, maxThroughputPercentage: 100 }, - { id: 5, maxThroughputPercentage: 100 }, + { id: 1, maxThroughputPercentage: 70, isDefaultBucket: false }, + { id: 2, maxThroughputPercentage: 80, isDefaultBucket: false }, + { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false }, ]); }); @@ -134,8 +134,8 @@ describe("ThroughputBucketsComponent", () => { , ); @@ -157,21 +157,21 @@ describe("ThroughputBucketsComponent", () => { fireEvent.click(toggles[0]); expect(mockOnBucketsChange).toHaveBeenCalledWith([ - { id: 1, maxThroughputPercentage: 100 }, - { id: 2, maxThroughputPercentage: 60 }, - { id: 3, maxThroughputPercentage: 100 }, - { id: 4, maxThroughputPercentage: 100 }, - { id: 5, maxThroughputPercentage: 100 }, + { id: 1, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 2, maxThroughputPercentage: 60, isDefaultBucket: false }, + { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false }, ]); fireEvent.click(toggles[0]); expect(mockOnBucketsChange).toHaveBeenCalledWith([ - { id: 1, maxThroughputPercentage: 50 }, - { id: 2, maxThroughputPercentage: 60 }, - { id: 3, maxThroughputPercentage: 100 }, - { id: 4, maxThroughputPercentage: 100 }, - { id: 5, maxThroughputPercentage: 100 }, + { id: 1, maxThroughputPercentage: 50, isDefaultBucket: false }, + { id: 2, maxThroughputPercentage: 60, isDefaultBucket: false }, + { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false }, + { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false }, ]); }); diff --git a/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.tsx b/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.tsx index 6d2bb9eb2..f81b7c2f9 100644 --- a/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.tsx +++ b/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent.tsx @@ -1,4 +1,16 @@ -import { Label, Slider, Stack, TextField, Toggle } from "@fluentui/react"; +import { + Dropdown, + Icon, + IDropdownOption, + Label, + Link, + Slider, + Stack, + Text, + TextField, + Toggle, + TooltipHost, +} from "@fluentui/react"; import { ThroughputBucket } from "Contracts/DataModels"; import { Keys, t } from "Localization"; import React, { FC, useEffect, useState } from "react"; @@ -9,6 +21,7 @@ const MAX_BUCKET_SIZES = 5; const DEFAULT_BUCKETS = Array.from({ length: MAX_BUCKET_SIZES }, (_, i) => ({ id: i + 1, maxThroughputPercentage: 100, + isDefaultBucket: false, })); export interface ThroughputBucketsComponentProps { @@ -24,19 +37,54 @@ export const ThroughputBucketsComponent: FC = ( onBucketsChange, onSaveableChange, }) => { + const NoDefaultThroughputSelectedKey: number = -1; const getThroughputBuckets = (buckets: ThroughputBucket[]): ThroughputBucket[] => { if (!buckets || buckets.length === 0) { return DEFAULT_BUCKETS; } const maxBuckets = Math.max(DEFAULT_BUCKETS.length, buckets.length); - const adjustedDefaultBuckets = Array.from({ length: maxBuckets }, (_, i) => ({ - id: i + 1, - maxThroughputPercentage: 100, + const adjustedDefaultBuckets: ThroughputBucket[] = Array.from( + { length: maxBuckets }, + (_, i) => + ({ + id: i + 1, + maxThroughputPercentage: 100, + isDefaultBucket: false, + }) as ThroughputBucket, + ); + + return adjustedDefaultBuckets.map((defaultBucket: ThroughputBucket) => { + const incoming: ThroughputBucket = buckets?.find((bucket) => bucket.id === defaultBucket.id); + + return { + ...defaultBucket, + ...incoming, + ...(incoming?.isDefaultBucket && { isDefaultBucket: true }), + }; + }); + }; + + const getThroughputBucketOptions = (): IDropdownOption[] => { + const noDefaultThroughputBucketSelected: IDropdownOption = { + key: NoDefaultThroughputSelectedKey, + text: t(Keys.controls.settings.throughputBuckets.noDefaultBucketSelected), + }; + + const throughputBucketOptions: IDropdownOption[] = throughputBuckets.map((bucket) => ({ + key: bucket.id, + text: t(Keys.controls.settings.throughputBuckets.bucketOptionLabel, { + id: String(bucket.id), + percentage: String(bucket.maxThroughputPercentage), + }), + disabled: bucket.maxThroughputPercentage === 100, + ...(bucket.maxThroughputPercentage === 100 && { + data: { + tooltip: t(Keys.controls.settings.throughputBuckets.bucketNotActive, { id: String(bucket.id) }), + }, + }), })); - return adjustedDefaultBuckets.map( - (defaultBucket) => buckets?.find((bucket) => bucket.id === defaultBucket.id) || defaultBucket, - ); + return [noDefaultThroughputBucketSelected, ...throughputBucketOptions]; }; const [throughputBuckets, setThroughputBuckets] = useState(getThroughputBuckets(currentBuckets)); @@ -53,7 +101,13 @@ export const ThroughputBucketsComponent: FC = ( const handleBucketChange = (id: number, newValue: number) => { const updatedBuckets = throughputBuckets.map((bucket) => - bucket.id === id ? { ...bucket, maxThroughputPercentage: newValue } : bucket, + bucket.id === id + ? { + ...bucket, + maxThroughputPercentage: newValue, + isDefaultBucket: newValue === 100 ? false : bucket.isDefaultBucket, + } + : bucket, ); setThroughputBuckets(updatedBuckets); const settingsChanged = isDirty(updatedBuckets, throughputBuckets); @@ -64,6 +118,38 @@ export const ThroughputBucketsComponent: FC = ( handleBucketChange(id, checked ? 50 : 100); }; + const onDefaultBucketToggle = (id: number, checked: boolean): void => { + const updatedBuckets: ThroughputBucket[] = throughputBuckets.map((bucket) => + bucket.id === id ? { ...bucket, isDefaultBucket: checked } : { ...bucket, isDefaultBucket: false }, + ); + setThroughputBuckets(updatedBuckets); + const settingsChanged = isDirty(updatedBuckets, throughputBuckets); + settingsChanged && onBucketsChange(updatedBuckets); + }; + + const onRenderDefaultThroughputBucketLabel = (): JSX.Element => { + const tooltipContent = (): JSX.Element => ( + + {t(Keys.controls.settings.throughputBuckets.defaultBucketTooltip)}{" "} + + {t(Keys.controls.settings.throughputBuckets.defaultBucketTooltipLearnMore)} + + + ); + + return ( + + + + + + + ); + }; + return ( ))} + throughputbucket.isDefaultBucket)?.id || + NoDefaultThroughputSelectedKey + } + onChange={(_, option) => onDefaultBucketToggle(option.key as number, true)} + onRenderLabel={onRenderDefaultThroughputBucketLabel} + onRenderOption={(option: IDropdownOption) => { + const tooltip: string = option?.data?.tooltip; + if (!tooltip) { + return <>{option?.text}; + } + + return ( + + {option?.text} + + ); + }} + styles={{ root: { width: "50%" } }} + data-test="default-throughput-bucket-dropdown" + /> ); }; diff --git a/src/Localization/en/Resources.json b/src/Localization/en/Resources.json index abf99a6a7..3331eb954 100644 --- a/src/Localization/en/Resources.json +++ b/src/Localization/en/Resources.json @@ -955,7 +955,14 @@ "bucketLabel": "Bucket {{id}}", "dataExplorerQueryBucket": " (Data Explorer Query Bucket)", "active": "Active", - "inactive": "Inactive" + "inactive": "Inactive", + "defaultBucketLabel": "Default Throughput Bucket", + "defaultBucketPlaceholder": "Select a default throughput bucket", + "defaultBucketTooltip": "The default throughput bucket is used for operations that do not specify a particular bucket.", + "defaultBucketTooltipLearnMore": "Learn more.", + "noDefaultBucketSelected": "No Default Throughput Bucket Selected", + "bucketOptionLabel": "Bucket {{id}} - {{percentage}}%", + "bucketNotActive": "Bucket {{id}} is not active." } } } diff --git a/test/sql/containercopy/permissionsScreen.spec.ts b/test/sql/containercopy/permissionsScreen.spec.ts index f592bf4c7..a36dc0aaf 100644 --- a/test/sql/containercopy/permissionsScreen.spec.ts +++ b/test/sql/containercopy/permissionsScreen.spec.ts @@ -20,7 +20,7 @@ test.describe("Container Copy - Permission Screen Verification", () => { }); test.afterEach("Cleanup after each test", async () => { - await page.unroute(/.*/, (route) => route.continue()); + await page.unrouteAll({ behavior: "ignoreErrors" }); await page.close(); }); diff --git a/test/sql/scaleAndSettings/computedProperties.spec.ts b/test/sql/scaleAndSettings/computedProperties.spec.ts index d1f95e53e..cc3d33f17 100644 --- a/test/sql/scaleAndSettings/computedProperties.spec.ts +++ b/test/sql/scaleAndSettings/computedProperties.spec.ts @@ -23,7 +23,9 @@ test.describe("Computed Properties", () => { }); test.afterAll("Delete Test Database", async () => { - await context?.dispose(); + if (!process.env.CI) { + await context?.dispose(); + } }); test("Add valid computed property", async ({ page }) => { diff --git a/test/sql/scaleAndSettings/throughputbucket.spec.ts b/test/sql/scaleAndSettings/throughputbucket.spec.ts new file mode 100644 index 000000000..1753c9b2e --- /dev/null +++ b/test/sql/scaleAndSettings/throughputbucket.spec.ts @@ -0,0 +1,108 @@ +import { expect, test } from "@playwright/test"; +import { CommandBarButton, DataExplorer, ONE_MINUTE_MS, TestAccount } from "../../fx"; +import { createTestSQLContainer, TestContainerContext } from "../../testData"; + +test.describe("Throughput bucket settings", () => { + let context: TestContainerContext = null!; + let explorer: DataExplorer = null!; + + test.beforeAll("Create Test Database", async () => { + context = await createTestSQLContainer(); + }); + + test.beforeEach("Open Throughput Bucket Settings", async ({ browser }) => { + const page = await browser.newPage(); + explorer = await DataExplorer.open(page, TestAccount.SQL); + + // Click Scale & Settings and open Throughput Bucket Settings tab + await explorer.openScaleAndSettings(context); + const throughputBucketTab = explorer.frame.getByTestId("settings-tab-header/ThroughputBucketsTab"); + await throughputBucketTab.click(); + }); + + // Delete database only if not running in CI + if (!process.env.CI) { + test.afterAll("Delete Test Database", async () => { + await context?.dispose(); + }); + } + + test("Activate throughput bucket #2", async () => { + // Activate bucket 2 + const bucket2Toggle = explorer.frame.getByTestId("bucket-2-active-toggle"); + await bucket2Toggle.click(); + + await explorer.commandBarButton(CommandBarButton.Save).click(); + await expect(explorer.getConsoleHeaderStatus()).toContainText( + `Successfully updated offer for collection ${context.container.id}`, + { + timeout: 2 * ONE_MINUTE_MS, + }, + ); + }); + + test("Activate throughput buckets #1 and #2", async () => { + // Activate bucket 1 + const bucket1Toggle = explorer.frame.getByTestId("bucket-1-active-toggle"); + await bucket1Toggle.click(); + + // Activate bucket 2 + const bucket2Toggle = explorer.frame.getByTestId("bucket-2-active-toggle"); + await bucket2Toggle.click(); + await explorer.commandBarButton(CommandBarButton.Save).click(); + await expect(explorer.getConsoleHeaderStatus()).toContainText( + `Successfully updated offer for collection ${context.container.id}`, + { + timeout: 2 * ONE_MINUTE_MS, + }, + ); + }); + + test("Set throughput percentage for bucket #1", async () => { + // Set throughput percentage for bucket 1 (inactive) - Should be disabled + const bucket1PercentageInput = explorer.frame.getByTestId("bucket-1-percentage-input"); + expect(bucket1PercentageInput).toBeDisabled(); + + // Activate bucket 1 + const bucket1Toggle = explorer.frame.getByTestId("bucket-1-active-toggle"); + await bucket1Toggle.click(); + expect(bucket1PercentageInput).toBeEnabled(); + await bucket1PercentageInput.fill("40"); + + await explorer.commandBarButton(CommandBarButton.Save).click(); + await expect(explorer.getConsoleHeaderStatus()).toContainText( + `Successfully updated offer for collection ${context.container.id}`, + { + timeout: 2 * ONE_MINUTE_MS, + }, + ); + }); + + test("Set default throughput bucket", async () => { + // There are no active throughput buckets so they all should be disabled + const defaultThroughputBucketDropdown = explorer.frame.getByTestId("default-throughput-bucket-dropdown"); + await defaultThroughputBucketDropdown.click(); + + const bucket1Option = explorer.frame.getByRole("option", { name: "Bucket 1" }); + expect(bucket1Option).toBeDisabled(); + + // Activate bucket 1 + const bucket1Toggle = explorer.frame.getByTestId("bucket-1-active-toggle"); + await bucket1Toggle.click(); + + // Open dropdown again + await defaultThroughputBucketDropdown.click(); + expect(bucket1Option).toBeEnabled(); + + // Select bucket 1 as default + await bucket1Option.click(); + + await explorer.commandBarButton(CommandBarButton.Save).click(); + await expect(explorer.getConsoleHeaderStatus()).toContainText( + `Successfully updated offer for collection ${context.container.id}`, + { + timeout: 2 * ONE_MINUTE_MS, + }, + ); + }); +}); diff --git a/test/testData.ts b/test/testData.ts index 494ce2e5d..e9ba759f1 100644 --- a/test/testData.ts +++ b/test/testData.ts @@ -223,10 +223,15 @@ export async function createTestSQLContainer({ const { database } = await client.databases.createIfNotExists({ id: databaseId }); try { - const { container } = await database.containers.createIfNotExists({ - id: containerId, - partitionKey, - }); + const { container } = await database.containers.createIfNotExists( + { + id: containerId, + partitionKey, + }, + { + offerThroughput: 4000, + }, + ); if (includeTestData) { const batchCount = TestData.length / 100; for (let i = 0; i < batchCount; i++) {