Merge branch 'master' of https://github.com/Azure/cosmos-explorer into users/jawelton/remove-sharedtput-041526

This commit is contained in:
Jade Welton
2026-04-17 14:34:30 -07:00
11 changed files with 392 additions and 130 deletions

189
package-lock.json generated
View File

@@ -13,7 +13,7 @@
"@azure/cosmos": "4.7.0", "@azure/cosmos": "4.7.0",
"@azure/cosmos-language-service": "0.0.5", "@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "4.5.0", "@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-class-properties": "7.12.1",
"@babel/plugin-proposal-decorators": "7.12.12", "@babel/plugin-proposal-decorators": "7.12.12",
"@fluentui/react": "8.119.0", "@fluentui/react": "8.119.0",
@@ -130,7 +130,7 @@
"@babel/preset-env": "7.24.7", "@babel/preset-env": "7.24.7",
"@babel/preset-react": "7.24.7", "@babel/preset-react": "7.24.7",
"@babel/preset-typescript": "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", "@testing-library/react": "11.2.3",
"@types/applicationinsights-js": "1.0.7", "@types/applicationinsights-js": "1.0.7",
"@types/codemirror": "0.0.56", "@types/codemirror": "0.0.56",
@@ -7099,19 +7099,23 @@
} }
}, },
"node_modules/@nteract/data-explorer/node_modules/react-dom": { "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", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0", "loose-envify": "^1.1.0",
"scheduler": "^0.23.0" "scheduler": "^0.23.2"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^18.2.0" "react": "^18.3.1"
} }
}, },
"node_modules/@nteract/data-explorer/node_modules/scheduler": { "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", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@@ -7649,24 +7653,17 @@
"react-redux": "^7.2.0" "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": { "node_modules/@nteract/mythic-configuration/node_modules/react-is": {
"version": "17.0.2", "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", "license": "MIT",
"peer": true "peer": true
}, },
"node_modules/@nteract/mythic-configuration/node_modules/react-redux": { "node_modules/@nteract/mythic-configuration/node_modules/react-redux": {
"version": "7.2.9", "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", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@@ -7718,24 +7715,17 @@
"react-redux": "^7.2.0" "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": { "node_modules/@nteract/mythic-notifications/node_modules/react-is": {
"version": "17.0.2", "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", "license": "MIT",
"peer": true "peer": true
}, },
"node_modules/@nteract/mythic-notifications/node_modules/react-redux": { "node_modules/@nteract/mythic-notifications/node_modules/react-redux": {
"version": "7.2.9", "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", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@@ -7987,6 +7977,8 @@
}, },
"node_modules/@octokit/auth-token": { "node_modules/@octokit/auth-token": {
"version": "4.0.0", "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", "license": "MIT",
"peer": true, "peer": true,
"engines": { "engines": {
@@ -7994,15 +7986,17 @@
} }
}, },
"node_modules/@octokit/core": { "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", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"@octokit/auth-token": "^4.0.0", "@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.0.0", "@octokit/graphql": "^7.1.0",
"@octokit/request": "^8.0.2", "@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.0.0", "@octokit/request-error": "^5.1.1",
"@octokit/types": "^12.0.0", "@octokit/types": "^13.0.0",
"before-after-hook": "^2.2.0", "before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0" "universal-user-agent": "^6.0.0"
}, },
@@ -8010,6 +8004,23 @@
"node": ">= 18" "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": { "node_modules/@octokit/endpoint": {
"version": "9.0.6", "version": "9.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
@@ -8036,18 +8047,37 @@
} }
}, },
"node_modules/@octokit/graphql": { "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", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"@octokit/request": "^8.0.1", "@octokit/request": "^8.4.1",
"@octokit/types": "^12.0.0", "@octokit/types": "^13.0.0",
"universal-user-agent": "^6.0.0" "universal-user-agent": "^6.0.0"
}, },
"engines": { "engines": {
"node": ">= 18" "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": { "node_modules/@octokit/openapi-types": {
"version": "20.0.0", "version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
@@ -8160,6 +8190,7 @@
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^6.0.3" "@octokit/types": "^6.0.3"
} }
@@ -8168,6 +8199,7 @@
"version": "6.41.0", "version": "6.41.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
"integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^12.11.0" "@octokit/openapi-types": "^12.11.0"
} }
@@ -8176,6 +8208,7 @@
"version": "2.5.4", "version": "2.5.4",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.5.4.tgz", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.5.4.tgz",
"integrity": "sha512-HCp8yKQfTITYK+Nd09MHzAlP1v3Ii/oCohv0/TW9rhSLvzb98BOVs2QmVYuloE6a3l6LsfyGIwb6Pc4ycgWlIQ==", "integrity": "sha512-HCp8yKQfTITYK+Nd09MHzAlP1v3Ii/oCohv0/TW9rhSLvzb98BOVs2QmVYuloE6a3l6LsfyGIwb6Pc4ycgWlIQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/auth-token": "^2.4.0", "@octokit/auth-token": "^2.4.0",
"@octokit/graphql": "^4.3.1", "@octokit/graphql": "^4.3.1",
@@ -8189,6 +8222,7 @@
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz",
"integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==",
"license": "ISC",
"dependencies": { "dependencies": {
"os-name": "^3.1.0" "os-name": "^3.1.0"
} }
@@ -8197,6 +8231,7 @@
"version": "4.8.0", "version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/request": "^5.6.0", "@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3", "@octokit/types": "^6.0.3",
@@ -8207,6 +8242,7 @@
"version": "6.41.0", "version": "6.41.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
"integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^12.11.0" "@octokit/openapi-types": "^12.11.0"
} }
@@ -8214,12 +8250,14 @@
"node_modules/@octokit/rest/node_modules/@octokit/openapi-types": { "node_modules/@octokit/rest/node_modules/@octokit/openapi-types": {
"version": "12.11.0", "version": "12.11.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", "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": { "node_modules/@octokit/rest/node_modules/@octokit/types": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz",
"integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==", "integrity": "sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@types/node": ">= 8" "@types/node": ">= 8"
} }
@@ -8547,12 +8585,12 @@
} }
}, },
"node_modules/@playwright/test": { "node_modules/@playwright/test": {
"version": "1.55.1", "version": "1.59.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz",
"integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"playwright": "1.55.1" "playwright": "1.59.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@@ -9785,7 +9823,6 @@
}, },
"node_modules/@types/react-redux": { "node_modules/@types/react-redux": {
"version": "7.1.7", "version": "7.1.7",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/hoist-non-react-statics": "^3.3.0", "@types/hoist-non-react-statics": "^3.3.0",
@@ -12731,6 +12768,9 @@
}, },
"node_modules/crypto": { "node_modules/crypto": {
"version": "1.0.1", "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", "license": "ISC",
"peer": true "peer": true
}, },
@@ -22340,21 +22380,13 @@
"dependencies": { "dependencies": {
"camelcase": "^3.0.0", "camelcase": "^3.0.0",
"less-vars-to-js": "^1.1.2", "less-vars-to-js": "^1.1.2",
"loader-utils": "^0.2.16", "loader-utils": "1.4.2",
"object.entries": "^1.0.3" "object.entries": "^1.0.3"
}, },
"engines": { "engines": {
"node": ">=5" "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": { "node_modules/less-vars-loader/node_modules/camelcase": {
"version": "3.0.0", "version": "3.0.0",
"dev": true, "dev": true,
@@ -22363,37 +22395,6 @@
"node": ">=0.10.0" "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": { "node_modules/less-vars-to-js": {
"version": "1.3.0", "version": "1.3.0",
"dev": true, "dev": true,
@@ -22663,6 +22664,7 @@
"version": "2.5.1", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz",
"integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==",
"license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
}, },
@@ -23438,6 +23440,7 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz",
"integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==",
"license": "MIT",
"dependencies": { "dependencies": {
"macos-release": "^2.2.0", "macos-release": "^2.2.0",
"windows-release": "^3.1.0" "windows-release": "^3.1.0"
@@ -23450,6 +23453,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@@ -23949,12 +23953,12 @@
"dev": true "dev": true
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.55.1", "version": "1.59.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz",
"integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"playwright-core": "1.55.1" "playwright-core": "1.59.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@@ -23967,9 +23971,9 @@
} }
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.55.1", "version": "1.59.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz",
"integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
"dev": true, "dev": true,
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
@@ -26773,6 +26777,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -29396,6 +29401,7 @@
"version": "3.3.3", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.3.tgz",
"integrity": "sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==", "integrity": "sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==",
"license": "MIT",
"dependencies": { "dependencies": {
"execa": "^1.0.0" "execa": "^1.0.0"
}, },
@@ -29410,6 +29416,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"license": "MIT",
"dependencies": { "dependencies": {
"cross-spawn": "^6.0.0", "cross-spawn": "^6.0.0",
"get-stream": "^4.0.0", "get-stream": "^4.0.0",
@@ -29427,6 +29434,7 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"license": "MIT",
"dependencies": { "dependencies": {
"pump": "^3.0.0" "pump": "^3.0.0"
}, },
@@ -29438,6 +29446,7 @@
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -29446,6 +29455,7 @@
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
"license": "MIT",
"dependencies": { "dependencies": {
"path-key": "^2.0.0" "path-key": "^2.0.0"
}, },
@@ -29457,6 +29467,7 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }

View File

@@ -8,7 +8,7 @@
"@azure/cosmos": "4.7.0", "@azure/cosmos": "4.7.0",
"@azure/cosmos-language-service": "0.0.5", "@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "4.5.0", "@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-class-properties": "7.12.1",
"@babel/plugin-proposal-decorators": "7.12.12", "@babel/plugin-proposal-decorators": "7.12.12",
"@fluentui/react": "8.119.0", "@fluentui/react": "8.119.0",
@@ -124,21 +124,23 @@
"d3-color": "3.1.0", "d3-color": "3.1.0",
"cross-spawn": "7.0.6", "cross-spawn": "7.0.6",
"less-vars-loader": { "less-vars-loader": {
"json5": "1.0.2" "json5": "1.0.2",
"loader-utils": "1.4.2"
}, },
"trim": "0.0.3", "trim": "0.0.3",
"@octokit/plugin-paginate-rest": "9.2.2", "@octokit/plugin-paginate-rest": "9.2.2",
"@octokit/request-error": "5.1.1", "@octokit/request-error": "5.1.1",
"@octokit/request": "8.4.1", "@octokit/request": "8.4.1",
"prismjs": "1.30.0", "prismjs": "1.30.0",
"sanitize-html": "2.17.0" "sanitize-html": "2.17.0",
"@types/react-redux": "7.1.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.29.0", "@babel/core": "7.29.0",
"@babel/preset-env": "7.24.7", "@babel/preset-env": "7.24.7",
"@babel/preset-react": "7.24.7", "@babel/preset-react": "7.24.7",
"@babel/preset-typescript": "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", "@testing-library/react": "11.2.3",
"@types/applicationinsights-js": "1.0.7", "@types/applicationinsights-js": "1.0.7",
"@types/codemirror": "0.0.56", "@types/codemirror": "0.0.56",

View File

@@ -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);

View File

@@ -347,6 +347,7 @@ export interface Offer {
export interface ThroughputBucket { export interface ThroughputBucket {
id: number; id: number;
maxThroughputPercentage: number; maxThroughputPercentage: number;
isDefaultBucket?: boolean;
} }
export interface SDKOfferDefinition extends Resource { export interface SDKOfferDefinition extends Resource {

View File

@@ -76,11 +76,11 @@ describe("ThroughputBucketsComponent", () => {
fireEvent.change(input, { target: { value: "70" } }); fireEvent.change(input, { target: { value: "70" } });
expect(mockOnBucketsChange).toHaveBeenCalledWith([ expect(mockOnBucketsChange).toHaveBeenCalledWith([
{ id: 1, maxThroughputPercentage: 70 }, { id: 1, maxThroughputPercentage: 70, isDefaultBucket: false },
{ id: 2, maxThroughputPercentage: 60 }, { id: 2, maxThroughputPercentage: 60, isDefaultBucket: false },
{ id: 3, maxThroughputPercentage: 100 }, { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 4, maxThroughputPercentage: 100 }, { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 5, maxThroughputPercentage: 100 }, { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
]); ]);
}); });
@@ -102,11 +102,11 @@ describe("ThroughputBucketsComponent", () => {
fireEvent.change(input2, { target: { value: "80" } }); fireEvent.change(input2, { target: { value: "80" } });
expect(mockOnBucketsChange).toHaveBeenCalledWith([ expect(mockOnBucketsChange).toHaveBeenCalledWith([
{ id: 1, maxThroughputPercentage: 70 }, { id: 1, maxThroughputPercentage: 70, isDefaultBucket: false },
{ id: 2, maxThroughputPercentage: 80 }, { id: 2, maxThroughputPercentage: 80, isDefaultBucket: false },
{ id: 3, maxThroughputPercentage: 100 }, { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 4, maxThroughputPercentage: 100 }, { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 5, maxThroughputPercentage: 100 }, { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
]); ]);
}); });
@@ -134,8 +134,8 @@ describe("ThroughputBucketsComponent", () => {
<ThroughputBucketsComponent <ThroughputBucketsComponent
{...defaultProps} {...defaultProps}
currentBuckets={[ currentBuckets={[
{ id: 1, maxThroughputPercentage: 100 }, { id: 1, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 2, maxThroughputPercentage: 50 }, { id: 2, maxThroughputPercentage: 50, isDefaultBucket: false },
]} ]}
/>, />,
); );
@@ -157,21 +157,21 @@ describe("ThroughputBucketsComponent", () => {
fireEvent.click(toggles[0]); fireEvent.click(toggles[0]);
expect(mockOnBucketsChange).toHaveBeenCalledWith([ expect(mockOnBucketsChange).toHaveBeenCalledWith([
{ id: 1, maxThroughputPercentage: 100 }, { id: 1, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 2, maxThroughputPercentage: 60 }, { id: 2, maxThroughputPercentage: 60, isDefaultBucket: false },
{ id: 3, maxThroughputPercentage: 100 }, { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 4, maxThroughputPercentage: 100 }, { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 5, maxThroughputPercentage: 100 }, { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
]); ]);
fireEvent.click(toggles[0]); fireEvent.click(toggles[0]);
expect(mockOnBucketsChange).toHaveBeenCalledWith([ expect(mockOnBucketsChange).toHaveBeenCalledWith([
{ id: 1, maxThroughputPercentage: 50 }, { id: 1, maxThroughputPercentage: 50, isDefaultBucket: false },
{ id: 2, maxThroughputPercentage: 60 }, { id: 2, maxThroughputPercentage: 60, isDefaultBucket: false },
{ id: 3, maxThroughputPercentage: 100 }, { id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 4, maxThroughputPercentage: 100 }, { id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
{ id: 5, maxThroughputPercentage: 100 }, { id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
]); ]);
}); });

View File

@@ -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 { ThroughputBucket } from "Contracts/DataModels";
import { Keys, t } from "Localization"; import { Keys, t } from "Localization";
import React, { FC, useEffect, useState } from "react"; 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) => ({ const DEFAULT_BUCKETS = Array.from({ length: MAX_BUCKET_SIZES }, (_, i) => ({
id: i + 1, id: i + 1,
maxThroughputPercentage: 100, maxThroughputPercentage: 100,
isDefaultBucket: false,
})); }));
export interface ThroughputBucketsComponentProps { export interface ThroughputBucketsComponentProps {
@@ -24,19 +37,54 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
onBucketsChange, onBucketsChange,
onSaveableChange, onSaveableChange,
}) => { }) => {
const NoDefaultThroughputSelectedKey: number = -1;
const getThroughputBuckets = (buckets: ThroughputBucket[]): ThroughputBucket[] => { const getThroughputBuckets = (buckets: ThroughputBucket[]): ThroughputBucket[] => {
if (!buckets || buckets.length === 0) { if (!buckets || buckets.length === 0) {
return DEFAULT_BUCKETS; return DEFAULT_BUCKETS;
} }
const maxBuckets = Math.max(DEFAULT_BUCKETS.length, buckets.length); const maxBuckets = Math.max(DEFAULT_BUCKETS.length, buckets.length);
const adjustedDefaultBuckets = Array.from({ length: maxBuckets }, (_, i) => ({ const adjustedDefaultBuckets: ThroughputBucket[] = Array.from(
{ length: maxBuckets },
(_, i) =>
({
id: i + 1, id: i + 1,
maxThroughputPercentage: 100, 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( return [noDefaultThroughputBucketSelected, ...throughputBucketOptions];
(defaultBucket) => buckets?.find((bucket) => bucket.id === defaultBucket.id) || defaultBucket,
);
}; };
const [throughputBuckets, setThroughputBuckets] = useState<ThroughputBucket[]>(getThroughputBuckets(currentBuckets)); const [throughputBuckets, setThroughputBuckets] = useState<ThroughputBucket[]>(getThroughputBuckets(currentBuckets));
@@ -53,7 +101,13 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
const handleBucketChange = (id: number, newValue: number) => { const handleBucketChange = (id: number, newValue: number) => {
const updatedBuckets = throughputBuckets.map((bucket) => 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); setThroughputBuckets(updatedBuckets);
const settingsChanged = isDirty(updatedBuckets, throughputBuckets); const settingsChanged = isDirty(updatedBuckets, throughputBuckets);
@@ -64,6 +118,38 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
handleBucketChange(id, checked ? 50 : 100); 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 => (
<Text>
{t(Keys.controls.settings.throughputBuckets.defaultBucketTooltip)}{" "}
<Link
href="https://learn.microsoft.com/azure/cosmos-db/throughput-buckets?tabs=dotnet#configuring-default-throughput-bucket"
target="_blank"
>
{t(Keys.controls.settings.throughputBuckets.defaultBucketTooltipLearnMore)}
</Link>
</Text>
);
return (
<Stack horizontal verticalAlign="center">
<Label>{t(Keys.controls.settings.throughputBuckets.defaultBucketLabel)}</Label>
<TooltipHost content={tooltipContent()}>
<Icon iconName="Info" styles={{ root: { marginLeft: 4, marginTop: 5 } }} />
</TooltipHost>
</Stack>
);
};
return ( return (
<Stack tokens={{ childrenGap: "m" }} styles={{ root: { width: "70%", maxWidth: 700 } }}> <Stack tokens={{ childrenGap: "m" }} styles={{ root: { width: "70%", maxWidth: 700 } }}>
<Label styles={{ root: { color: "var(--colorNeutralForeground1)" } }}> <Label styles={{ root: { color: "var(--colorNeutralForeground1)" } }}>
@@ -102,6 +188,7 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
fieldGroup: { width: 80 }, fieldGroup: { width: 80 },
}} }}
disabled={bucket.maxThroughputPercentage === 100} disabled={bucket.maxThroughputPercentage === 100}
data-test={`bucket-${bucket.id}-percentage-input`}
/> />
<Toggle <Toggle
onText={t(Keys.controls.settings.throughputBuckets.active)} onText={t(Keys.controls.settings.throughputBuckets.active)}
@@ -112,10 +199,36 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
root: { marginBottom: 0 }, root: { marginBottom: 0 },
text: { fontSize: 12, color: "var(--colorNeutralForeground1)" }, text: { fontSize: 12, color: "var(--colorNeutralForeground1)" },
}} }}
data-test={`bucket-${bucket.id}-active-toggle`}
></Toggle> ></Toggle>
</Stack> </Stack>
))} ))}
</Stack> </Stack>
<Dropdown
placeholder={t(Keys.controls.settings.throughputBuckets.defaultBucketPlaceholder)}
label={t(Keys.controls.settings.throughputBuckets.defaultBucketLabel)}
options={getThroughputBucketOptions()}
selectedKey={
throughputBuckets?.find((throughputbucket: ThroughputBucket) => 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 (
<TooltipHost content={tooltip}>
<span>{option?.text}</span>
</TooltipHost>
);
}}
styles={{ root: { width: "50%" } }}
data-test="default-throughput-bucket-dropdown"
/>
</Stack> </Stack>
); );
}; };

View File

@@ -955,7 +955,14 @@
"bucketLabel": "Bucket {{id}}", "bucketLabel": "Bucket {{id}}",
"dataExplorerQueryBucket": " (Data Explorer Query Bucket)", "dataExplorerQueryBucket": " (Data Explorer Query Bucket)",
"active": "Active", "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."
} }
} }
} }

View File

@@ -20,7 +20,7 @@ test.describe("Container Copy - Permission Screen Verification", () => {
}); });
test.afterEach("Cleanup after each test", async () => { test.afterEach("Cleanup after each test", async () => {
await page.unroute(/.*/, (route) => route.continue()); await page.unrouteAll({ behavior: "ignoreErrors" });
await page.close(); await page.close();
}); });

View File

@@ -23,7 +23,9 @@ test.describe("Computed Properties", () => {
}); });
test.afterAll("Delete Test Database", async () => { test.afterAll("Delete Test Database", async () => {
if (!process.env.CI) {
await context?.dispose(); await context?.dispose();
}
}); });
test("Add valid computed property", async ({ page }) => { test("Add valid computed property", async ({ page }) => {

View File

@@ -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,
},
);
});
});

View File

@@ -223,10 +223,15 @@ export async function createTestSQLContainer({
const { database } = await client.databases.createIfNotExists({ id: databaseId }); const { database } = await client.databases.createIfNotExists({ id: databaseId });
try { try {
const { container } = await database.containers.createIfNotExists({ const { container } = await database.containers.createIfNotExists(
{
id: containerId, id: containerId,
partitionKey, partitionKey,
}); },
{
offerThroughput: 4000,
},
);
if (includeTestData) { if (includeTestData) {
const batchCount = TestData.length / 100; const batchCount = TestData.length / 100;
for (let i = 0; i < batchCount; i++) { for (let i = 0; i < batchCount; i++) {