mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-07 19:46:53 +00:00
Compare commits
10 Commits
dependabot
...
users/aisa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a96f4bbb46 | ||
|
|
8075ef2847 | ||
|
|
063ad23bce | ||
|
|
eacbeae417 | ||
|
|
94158504a8 | ||
|
|
9b032ecae4 | ||
|
|
6493c985b4 | ||
|
|
569167fa10 | ||
|
|
6e267b2bba | ||
|
|
282004b09b |
269
package-lock.json
generated
269
package-lock.json
generated
@@ -179,10 +179,11 @@
|
||||
}
|
||||
},
|
||||
"@azure/cosmos": {
|
||||
"version": "3.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.2.tgz",
|
||||
"integrity": "sha512-sceY5LWj0BHGj8PSyaVCfDRQLVZyoCfIY78kyIROJVEw0k+p9XFs8fhpykN8JklkCftL0WlaVY+X25SQwnhZsw==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://msazure.pkgs.visualstudio.com/_packaging/AzurePortal/npm/registry/@azure/cosmos/-/cosmos-4.0.0.tgz",
|
||||
"integrity": "sha1-X9qLNctiu82lIVm5bEw5gahD1bk=",
|
||||
"requires": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.2.0",
|
||||
"debug": "^4.1.1",
|
||||
@@ -533,11 +534,6 @@
|
||||
"regexpu-core": "^4.7.1"
|
||||
}
|
||||
},
|
||||
"@babel/helper-environment-visitor": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="
|
||||
},
|
||||
"@babel/helper-explode-assignable-expression": {
|
||||
"version": "7.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz",
|
||||
@@ -625,7 +621,24 @@
|
||||
"@babel/parser": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
|
||||
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw=="
|
||||
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
|
||||
"integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.12.13",
|
||||
"@babel/generator": "^7.13.9",
|
||||
"@babel/helper-function-name": "^7.12.13",
|
||||
"@babel/helper-split-export-declaration": "^7.12.13",
|
||||
"@babel/parser": "^7.13.13",
|
||||
"@babel/types": "^7.13.13",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.13.14",
|
||||
@@ -706,6 +719,28 @@
|
||||
"@babel/types": "^7.12.13"
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
|
||||
"integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.12.13",
|
||||
"@babel/generator": "^7.13.9",
|
||||
"@babel/helper-function-name": "^7.12.13",
|
||||
"@babel/helper-split-export-declaration": "^7.12.13",
|
||||
"@babel/parser": "^7.13.13",
|
||||
"@babel/types": "^7.13.13",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/parser": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
|
||||
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.13.14",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz",
|
||||
@@ -783,6 +818,21 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
|
||||
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw=="
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
|
||||
"integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.12.13",
|
||||
"@babel/generator": "^7.13.9",
|
||||
"@babel/helper-function-name": "^7.12.13",
|
||||
"@babel/helper-split-export-declaration": "^7.12.13",
|
||||
"@babel/parser": "^7.13.13",
|
||||
"@babel/types": "^7.13.13",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.13.14",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz",
|
||||
@@ -844,11 +894,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/helper-string-parser": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
|
||||
@@ -883,6 +928,30 @@
|
||||
"@babel/types": "^7.12.13"
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
|
||||
"integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.12.13",
|
||||
"@babel/generator": "^7.13.9",
|
||||
"@babel/helper-function-name": "^7.12.13",
|
||||
"@babel/helper-split-export-declaration": "^7.12.13",
|
||||
"@babel/parser": "^7.13.13",
|
||||
"@babel/types": "^7.13.13",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/parser": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
|
||||
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.13.14",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz",
|
||||
@@ -916,6 +985,28 @@
|
||||
"@babel/types": "^7.12.13"
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
|
||||
"integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.12.13",
|
||||
"@babel/generator": "^7.13.9",
|
||||
"@babel/helper-function-name": "^7.12.13",
|
||||
"@babel/helper-split-export-declaration": "^7.12.13",
|
||||
"@babel/parser": "^7.13.13",
|
||||
"@babel/types": "^7.13.13",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/parser": {
|
||||
"version": "7.13.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
|
||||
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.13.14",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz",
|
||||
@@ -1941,107 +2032,19 @@
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||
"version": "7.12.12",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz",
|
||||
"integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/generator": "^7.23.0",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/types": "^7.23.0",
|
||||
"@babel/code-frame": "^7.12.11",
|
||||
"@babel/generator": "^7.12.11",
|
||||
"@babel/helper-function-name": "^7.12.11",
|
||||
"@babel/helper-split-export-declaration": "^7.12.11",
|
||||
"@babel/parser": "^7.12.11",
|
||||
"@babel/types": "^7.12.12",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.22.13",
|
||||
"chalk": "^2.4.2"
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.23.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jsesc": "^2.5.1"
|
||||
}
|
||||
},
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"requires": {
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-hoist-variables": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
|
||||
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw=="
|
||||
},
|
||||
"@babel/template": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/types": "^7.22.15"
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"requires": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
}
|
||||
"globals": "^11.1.0",
|
||||
"lodash": "^4.17.19"
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
@@ -4006,40 +4009,6 @@
|
||||
"@types/yargs": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"requires": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
}
|
||||
},
|
||||
"@jridgewell/resolve-uri": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA=="
|
||||
},
|
||||
"@jridgewell/set-array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
|
||||
},
|
||||
"@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.19",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
||||
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"@jupyterlab/apputils": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@jupyterlab/apputils/-/apputils-3.0.2.tgz",
|
||||
@@ -22165,6 +22134,12 @@
|
||||
"resolved": "https://registry.npmjs.org/react-splitter-layout/-/react-splitter-layout-4.0.0.tgz",
|
||||
"integrity": "sha512-SLqOjBOxRuizWUa83w6q5/u9cDWa9/yj9Iko9V9JFN8x+cqIXiDlUFWSx+icz3IIgvsN/oRIw3za5/32RjIwrA=="
|
||||
},
|
||||
"react-string-format": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://msazure.pkgs.visualstudio.com/_packaging/AzurePortal/npm/registry/react-string-format/-/react-string-format-1.0.1.tgz",
|
||||
"integrity": "sha1-JyQaRZHqURInBBx64HC3FJBh3AA=",
|
||||
"license": "MIT"
|
||||
},
|
||||
"react-syntax-highlighter": {
|
||||
"version": "12.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@azure/arm-cosmosdb": "9.1.0",
|
||||
"@azure/cosmos": "3.16.2",
|
||||
"@azure/cosmos": "4.0.0",
|
||||
"@azure/cosmos-language-service": "0.0.5",
|
||||
"@azure/identity": "1.2.1",
|
||||
"@azure/ms-rest-nodeauth": "3.0.7",
|
||||
@@ -92,6 +92,7 @@
|
||||
"react-notification-system": "0.2.17",
|
||||
"react-redux": "7.1.3",
|
||||
"react-splitter-layout": "4.0.0",
|
||||
"react-string-format": "1.0.1",
|
||||
"react-youtube": "9.0.1",
|
||||
"redux": "4.0.4",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -234,4 +235,4 @@
|
||||
"printWidth": 120,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,12 +427,6 @@ export class JunoEndpoints {
|
||||
public static readonly Stage = "https://tools-staging.cosmos.azure.com";
|
||||
}
|
||||
|
||||
export class PriorityLevel {
|
||||
public static readonly High = "high";
|
||||
public static readonly Low = "low";
|
||||
public static readonly Default = "low";
|
||||
}
|
||||
|
||||
export const QueryCopilotSampleDatabaseId = "CopilotSampleDb";
|
||||
export const QueryCopilotSampleContainerId = "SampleContainer";
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ describe("requestPlugin", () => {
|
||||
const headers = {};
|
||||
const endpoint = "https://docs.azure.com";
|
||||
const path = "/dbs/foo";
|
||||
requestPlugin({ endpoint, headers, path } as any, next as any);
|
||||
requestPlugin({ endpoint, headers, path } as any, undefined, next as any);
|
||||
expect(next.mock.calls[0][0]).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -137,7 +137,7 @@ describe("requestPlugin", () => {
|
||||
const headers = {};
|
||||
const endpoint = "";
|
||||
const path = "/dbs/foo";
|
||||
requestPlugin({ endpoint, headers, path } as any, next as any);
|
||||
requestPlugin({ endpoint, headers, path } as any, undefined, next as any);
|
||||
expect(next.mock.calls[0][0]).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import * as Cosmos from "@azure/cosmos";
|
||||
import { sendCachedDataMessage } from "Common/MessageHandler";
|
||||
import { AuthorizationToken, MessageTypes } from "Contracts/MessageTypes";
|
||||
import { AuthType } from "../AuthType";
|
||||
import { PriorityLevel } from "../Common/Constants";
|
||||
import { Platform, configContext } from "../ConfigContext";
|
||||
import { userContext } from "../UserContext";
|
||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||
@@ -51,7 +49,7 @@ export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => {
|
||||
return decodeURIComponent(result.PrimaryReadWriteToken);
|
||||
};
|
||||
|
||||
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, next) => {
|
||||
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, diagnosticNode, next) => {
|
||||
requestContext.endpoint = new URL(configContext.PROXY_PATH, window.location.href).href;
|
||||
requestContext.headers["x-ms-proxy-target"] = endpoint();
|
||||
return next(requestContext);
|
||||
@@ -109,18 +107,6 @@ export function client(): Cosmos.CosmosClient {
|
||||
_defaultHeaders["x-ms-cosmos-sdk-supportedcapabilities"] =
|
||||
SDKSupportedCapabilities.None | SDKSupportedCapabilities.PartitionMerge;
|
||||
|
||||
if (
|
||||
userContext.authType === AuthType.ConnectionString ||
|
||||
userContext.authType === AuthType.EncryptedToken ||
|
||||
userContext.authType === AuthType.ResourceToken
|
||||
) {
|
||||
// Default to low priority. Needed for non-AAD-auth scenarios
|
||||
// where we cannot use RP API, and thus, cannot detect whether priority
|
||||
// based execution is enabled.
|
||||
// The header will be ignored if priority based execution is disabled on the account.
|
||||
_defaultHeaders["x-ms-cosmos-priority-level"] = PriorityLevel.Default;
|
||||
}
|
||||
|
||||
const options: Cosmos.CosmosClientOptions = {
|
||||
endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
|
||||
key: userContext.masterKey,
|
||||
|
||||
@@ -689,9 +689,9 @@ export default class Explorer {
|
||||
private _initSettings() {
|
||||
if (!ExplorerSettings.hasSettingsDefined()) {
|
||||
ExplorerSettings.createDefaultSettings();
|
||||
} else {
|
||||
ExplorerSettings.ensurePriorityLevel();
|
||||
}
|
||||
|
||||
ExplorerSettings.ensurePriorityLevel();
|
||||
}
|
||||
|
||||
public uploadFile(
|
||||
|
||||
@@ -67,7 +67,7 @@ export function createStaticCommandBarButtons(
|
||||
}
|
||||
}
|
||||
|
||||
if (userContext.apiType !== "Tables") {
|
||||
if (userContext.apiType !== "Tables" && configContext.platform !== Platform.Fabric) {
|
||||
newCollectionBtn.children = [createNewCollectionGroup(container)];
|
||||
const newDatabaseBtn = createNewDatabase(container);
|
||||
newCollectionBtn.children.push(newDatabaseBtn);
|
||||
|
||||
@@ -114,7 +114,8 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
createNewDatabase: userContext.apiType !== "Tables" && !this.props.databaseId,
|
||||
createNewDatabase:
|
||||
userContext.apiType !== "Tables" && configContext.platform !== Platform.Fabric && !this.props.databaseId,
|
||||
newDatabaseId: props.isQuickstart ? this.getSampleDBName() : "",
|
||||
isSharedThroughputChecked: this.getSharedThroughputDefault(),
|
||||
selectedDatabaseId:
|
||||
@@ -274,36 +275,38 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
</TooltipHost>
|
||||
</Stack>
|
||||
|
||||
<Stack horizontal verticalAlign="center">
|
||||
<div role="radiogroup">
|
||||
<input
|
||||
className="panelRadioBtn"
|
||||
checked={this.state.createNewDatabase}
|
||||
aria-label="Create new database"
|
||||
aria-checked={this.state.createNewDatabase}
|
||||
name="databaseType"
|
||||
type="radio"
|
||||
role="radio"
|
||||
id="databaseCreateNew"
|
||||
tabIndex={0}
|
||||
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
|
||||
/>
|
||||
<span className="panelRadioBtnLabel">Create new</span>
|
||||
{configContext.platform !== Platform.Fabric && (
|
||||
<Stack horizontal verticalAlign="center">
|
||||
<div role="radiogroup">
|
||||
<input
|
||||
className="panelRadioBtn"
|
||||
checked={this.state.createNewDatabase}
|
||||
aria-label="Create new database"
|
||||
aria-checked={this.state.createNewDatabase}
|
||||
name="databaseType"
|
||||
type="radio"
|
||||
role="radio"
|
||||
id="databaseCreateNew"
|
||||
tabIndex={0}
|
||||
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
|
||||
/>
|
||||
<span className="panelRadioBtnLabel">Create new</span>
|
||||
|
||||
<input
|
||||
className="panelRadioBtn"
|
||||
checked={!this.state.createNewDatabase}
|
||||
aria-label="Use existing database"
|
||||
aria-checked={!this.state.createNewDatabase}
|
||||
name="databaseType"
|
||||
type="radio"
|
||||
role="radio"
|
||||
tabIndex={0}
|
||||
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
|
||||
/>
|
||||
<span className="panelRadioBtnLabel">Use existing</span>
|
||||
</div>
|
||||
</Stack>
|
||||
<input
|
||||
className="panelRadioBtn"
|
||||
checked={!this.state.createNewDatabase}
|
||||
aria-label="Use existing database"
|
||||
aria-checked={!this.state.createNewDatabase}
|
||||
name="databaseType"
|
||||
type="radio"
|
||||
role="radio"
|
||||
tabIndex={0}
|
||||
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
|
||||
/>
|
||||
<span className="panelRadioBtnLabel">Use existing</span>
|
||||
</div>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{this.state.createNewDatabase && (
|
||||
<Stack className="panelGroupSpacing">
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
import { Checkbox, ChoiceGroup, IChoiceGroupOption, SpinButton } from "@fluentui/react";
|
||||
import { PriorityLevel } from "@azure/cosmos";
|
||||
import {
|
||||
Checkbox,
|
||||
ChoiceGroup,
|
||||
IChoiceGroupOption,
|
||||
ISpinButtonStyles,
|
||||
IToggleStyles,
|
||||
Position,
|
||||
SpinButton,
|
||||
Toggle,
|
||||
} from "@fluentui/react";
|
||||
import * as Constants from "Common/Constants";
|
||||
import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
|
||||
import { configContext } from "ConfigContext";
|
||||
@@ -6,10 +16,10 @@ import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import * as StringUtility from "Shared/StringUtility";
|
||||
import { userContext } from "UserContext";
|
||||
import { logConsoleInfo } from "Utils/NotificationConsoleUtils";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import React, { FunctionComponent, MouseEvent, useState } from "react";
|
||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||
import * as PriorityBasedExecutionUtils from "Utils/PriorityBasedExecutionUtils";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import React, { FunctionComponent, useState } from "react";
|
||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||
|
||||
export const SettingsPane: FunctionComponent = () => {
|
||||
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
||||
@@ -19,6 +29,13 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
? Constants.Queries.UnlimitedPageOption
|
||||
: Constants.Queries.CustomPageOption,
|
||||
);
|
||||
const [queryTimeoutEnabled, setQueryTimeoutEnabled] = useState<boolean>(
|
||||
LocalStorageUtility.getEntryBoolean(StorageKey.QueryTimeoutEnabled),
|
||||
);
|
||||
const [queryTimeout, setQueryTimeout] = useState<number>(LocalStorageUtility.getEntryNumber(StorageKey.QueryTimeout));
|
||||
const [automaticallyCancelQueryAfterTimeout, setAutomaticallyCancelQueryAfterTimeout] = useState<boolean>(
|
||||
LocalStorageUtility.getEntryBoolean(StorageKey.AutomaticallyCancelQueryAfterTimeout),
|
||||
);
|
||||
const [customItemPerPage, setCustomItemPerPage] = useState<number>(
|
||||
LocalStorageUtility.getEntryNumber(StorageKey.CustomItemPerPage) || 0,
|
||||
);
|
||||
@@ -42,10 +59,10 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
? LocalStorageUtility.getEntryNumber(StorageKey.MaxDegreeOfParellism)
|
||||
: Constants.Queries.DefaultMaxDegreeOfParallelism,
|
||||
);
|
||||
const [priorityLevel, setPriorityLevel] = useState<string>(
|
||||
const [priorityLevel, setPriorityLevel] = useState<PriorityLevel>(
|
||||
LocalStorageUtility.hasItem(StorageKey.PriorityLevel)
|
||||
? LocalStorageUtility.getEntryString(StorageKey.PriorityLevel)
|
||||
: Constants.PriorityLevel.Default,
|
||||
? (LocalStorageUtility.getEntryString(StorageKey.PriorityLevel) as PriorityLevel)
|
||||
: PriorityLevel.Low,
|
||||
);
|
||||
const explorerVersion = configContext.gitSha;
|
||||
const shouldShowQueryPageOptions = userContext.apiType === "SQL";
|
||||
@@ -53,7 +70,7 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
const shouldShowCrossPartitionOption = userContext.apiType !== "Gremlin";
|
||||
const shouldShowParallelismOption = userContext.apiType !== "Gremlin";
|
||||
const shouldShowPriorityLevelOption = PriorityBasedExecutionUtils.isFeatureEnabled();
|
||||
const handlerOnSubmit = (e: MouseEvent<HTMLButtonElement>) => {
|
||||
const handlerOnSubmit = () => {
|
||||
setIsExecuting(true);
|
||||
|
||||
LocalStorageUtility.setEntryNumber(
|
||||
@@ -61,10 +78,11 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
isCustomPageOptionSelected() ? customItemPerPage : Constants.Queries.unlimitedItemsPerPage,
|
||||
);
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.CustomItemPerPage, customItemPerPage);
|
||||
LocalStorageUtility.setEntryBoolean(StorageKey.QueryTimeoutEnabled, queryTimeoutEnabled);
|
||||
LocalStorageUtility.setEntryString(StorageKey.ContainerPaginationEnabled, containerPaginationEnabled.toString());
|
||||
LocalStorageUtility.setEntryString(StorageKey.IsCrossPartitionQueryEnabled, crossPartitionQueryEnabled.toString());
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.MaxDegreeOfParellism, maxDegreeOfParallelism);
|
||||
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, priorityLevel.toString());
|
||||
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, priorityLevel);
|
||||
|
||||
if (shouldShowGraphAutoVizOption) {
|
||||
LocalStorageUtility.setEntryBoolean(
|
||||
@@ -73,6 +91,14 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (queryTimeoutEnabled) {
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.QueryTimeout, queryTimeout);
|
||||
LocalStorageUtility.setEntryBoolean(
|
||||
StorageKey.AutomaticallyCancelQueryAfterTimeout,
|
||||
automaticallyCancelQueryAfterTimeout,
|
||||
);
|
||||
}
|
||||
|
||||
setIsExecuting(false);
|
||||
logConsoleInfo(
|
||||
`Updated items per page setting to ${LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage)}`,
|
||||
@@ -97,7 +123,6 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
`Updated query setting to ${LocalStorageUtility.getEntryString(StorageKey.SetPartitionKeyUndefined)}`,
|
||||
);
|
||||
closeSidePanel();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const isCustomPageOptionSelected = () => {
|
||||
@@ -112,7 +137,7 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
formError: "",
|
||||
isExecuting,
|
||||
submitButtonText: "Apply",
|
||||
onSubmit: () => handlerOnSubmit(undefined),
|
||||
onSubmit: () => handlerOnSubmit(),
|
||||
};
|
||||
const pageOptionList: IChoiceGroupOption[] = [
|
||||
{ key: Constants.Queries.CustomPageOption, text: "Custom" },
|
||||
@@ -125,21 +150,36 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
];
|
||||
|
||||
const priorityLevelOptionList: IChoiceGroupOption[] = [
|
||||
{ key: Constants.PriorityLevel.Low, text: "Low" },
|
||||
{ key: Constants.PriorityLevel.High, text: "High" },
|
||||
{ key: PriorityLevel.Low, text: "Low" },
|
||||
{ key: PriorityLevel.High, text: "High" },
|
||||
];
|
||||
|
||||
const handleOnPriorityLevelOptionChange = (
|
||||
ev: React.FormEvent<HTMLInputElement>,
|
||||
option: IChoiceGroupOption,
|
||||
): void => {
|
||||
setPriorityLevel(option.key);
|
||||
setPriorityLevel(option.key as PriorityLevel);
|
||||
};
|
||||
|
||||
const handleOnPageOptionChange = (ev: React.FormEvent<HTMLInputElement>, option: IChoiceGroupOption): void => {
|
||||
setPageOption(option.key);
|
||||
};
|
||||
|
||||
const handleOnQueryTimeoutToggleChange = (ev: React.MouseEvent<HTMLElement>, checked?: boolean): void => {
|
||||
setQueryTimeoutEnabled(checked);
|
||||
};
|
||||
|
||||
const handleOnAutomaticallyCancelQueryToggleChange = (ev: React.MouseEvent<HTMLElement>, checked?: boolean): void => {
|
||||
setAutomaticallyCancelQueryAfterTimeout(checked);
|
||||
};
|
||||
|
||||
const handleOnQueryTimeoutSpinButtonChange = (ev: React.MouseEvent<HTMLElement>, newValue?: string): void => {
|
||||
const queryTimeout = Number(newValue);
|
||||
if (!isNaN(queryTimeout)) {
|
||||
setQueryTimeout(queryTimeout);
|
||||
}
|
||||
};
|
||||
|
||||
const choiceButtonStyles = {
|
||||
root: {
|
||||
clear: "both",
|
||||
@@ -161,6 +201,35 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const queryTimeoutToggleStyles: IToggleStyles = {
|
||||
label: {
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
display: "block",
|
||||
},
|
||||
root: {},
|
||||
container: {},
|
||||
pill: {},
|
||||
thumb: {},
|
||||
text: {},
|
||||
};
|
||||
|
||||
const queryTimeoutSpinButtonStyles: ISpinButtonStyles = {
|
||||
label: {
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
},
|
||||
root: {
|
||||
paddingBottom: 10,
|
||||
},
|
||||
labelWrapper: {},
|
||||
icon: {},
|
||||
spinButtonWrapper: {},
|
||||
input: {},
|
||||
arrowButtonsContainer: {},
|
||||
};
|
||||
|
||||
return (
|
||||
<RightPaneForm {...genericPaneProps}>
|
||||
<div className="paneMainContent">
|
||||
@@ -211,6 +280,50 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{userContext.apiType === "SQL" && (
|
||||
<div className="settingsSection">
|
||||
<div className="settingsSectionPart">
|
||||
<div>
|
||||
<legend id="queryTimeoutLabel" className="settingsSectionLabel legendLabel">
|
||||
Query Timeout
|
||||
</legend>
|
||||
<InfoTooltip>
|
||||
When a query reaches a specified time limit, a popup with an option to cancel the query will show
|
||||
unless automatic cancellation has been enabled
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<div>
|
||||
<Toggle
|
||||
styles={queryTimeoutToggleStyles}
|
||||
label="Enable query timeout"
|
||||
onChange={handleOnQueryTimeoutToggleChange}
|
||||
defaultChecked={queryTimeoutEnabled}
|
||||
/>
|
||||
</div>
|
||||
{queryTimeoutEnabled && (
|
||||
<div>
|
||||
<SpinButton
|
||||
label="Query timeout (ms)"
|
||||
labelPosition={Position.top}
|
||||
defaultValue={(queryTimeout || 5000).toString()}
|
||||
min={100}
|
||||
step={1000}
|
||||
onChange={handleOnQueryTimeoutSpinButtonChange}
|
||||
incrementButtonAriaLabel="Increase value by 1000"
|
||||
decrementButtonAriaLabel="Decrease value by 1000"
|
||||
styles={queryTimeoutSpinButtonStyles}
|
||||
/>
|
||||
<Toggle
|
||||
label="Automatically cancel query after timeout"
|
||||
styles={queryTimeoutToggleStyles}
|
||||
onChange={handleOnAutomaticallyCancelQueryToggleChange}
|
||||
defaultChecked={automaticallyCancelQueryAfterTimeout}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="settingsSection">
|
||||
<div className="settingsSectionPart">
|
||||
<div className="settingsSectionLabel">
|
||||
@@ -289,8 +402,7 @@ export const SettingsPane: FunctionComponent = () => {
|
||||
</legend>
|
||||
<InfoTooltip>
|
||||
Sets the priority level for data-plane requests from Data Explorer when using Priority-Based
|
||||
Execution. If "None" is selected, Data Explorer will not specify priority level, and the
|
||||
server-side default priority level will be used.
|
||||
Execution.
|
||||
</InfoTooltip>
|
||||
<ChoiceGroup
|
||||
ariaLabelledBy="priorityLevel"
|
||||
|
||||
@@ -97,6 +97,46 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="settingsSection"
|
||||
>
|
||||
<div
|
||||
className="settingsSectionPart"
|
||||
>
|
||||
<div>
|
||||
<legend
|
||||
className="settingsSectionLabel legendLabel"
|
||||
id="queryTimeoutLabel"
|
||||
>
|
||||
Query Timeout
|
||||
</legend>
|
||||
<InfoTooltip>
|
||||
When a query reaches a specified time limit, a popup with an option to cancel the query will show unless automatic cancellation has been enabled
|
||||
</InfoTooltip>
|
||||
</div>
|
||||
<div>
|
||||
<StyledToggleBase
|
||||
defaultChecked={false}
|
||||
label="Enable query timeout"
|
||||
onChange={[Function]}
|
||||
styles={
|
||||
Object {
|
||||
"container": Object {},
|
||||
"label": Object {
|
||||
"display": "block",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 400,
|
||||
},
|
||||
"pill": Object {},
|
||||
"root": Object {},
|
||||
"text": Object {},
|
||||
"thumb": Object {},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="settingsSection"
|
||||
>
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<button
|
||||
class="filterbtnstyle queryButton"
|
||||
data-bind="
|
||||
click: refreshDocumentsGrid,
|
||||
click: refreshDocumentsGrid.bind($data, true),
|
||||
enable: applyFilterButton.enabled"
|
||||
aria-label="Apply filter"
|
||||
tabindex="0"
|
||||
@@ -176,7 +176,7 @@
|
||||
<img
|
||||
class="refreshcol"
|
||||
src="/refresh-cosmos.svg"
|
||||
data-bind="click: refreshDocumentsGrid"
|
||||
data-bind="click: refreshDocumentsGrid.bind($data, false)"
|
||||
alt="Refresh documents"
|
||||
tabindex="0"
|
||||
/>
|
||||
@@ -209,7 +209,10 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="loadMore">
|
||||
<a role="button" data-bind="click: loadNextPage, event: { keypress: onLoadMoreKeyInput }" tabindex="0"
|
||||
<a
|
||||
role="button"
|
||||
data-bind="click: loadNextPage.bind($data, false), event: { keypress: onLoadMoreKeyInput }"
|
||||
tabindex="0"
|
||||
>Load more</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { extractPartitionKey, ItemDefinition, PartitionKeyDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||
import { ItemDefinition, PartitionKey, PartitionKeyDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||
import { querySampleDocuments, readSampleDocument } from "Explorer/QueryCopilot/QueryCopilotUtilities";
|
||||
import * as ko from "knockout";
|
||||
import Q from "q";
|
||||
import { format } from "react-string-format";
|
||||
import { QueryConstants } from "Shared/Constants";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import DeleteDocumentIcon from "../../../images/DeleteDocument.svg";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import NewDocumentIcon from "../../../images/NewDocument.svg";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
import UploadIcon from "../../../images/Upload_16x16.svg";
|
||||
import DiscardIcon from "../../../images/discard.svg";
|
||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import {
|
||||
DocumentsGridMetrics,
|
||||
@@ -14,15 +17,15 @@ import {
|
||||
QueryCopilotSampleContainerId,
|
||||
QueryCopilotSampleDatabaseId,
|
||||
} from "../../Common/Constants";
|
||||
import editable from "../../Common/EditableUtility";
|
||||
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
||||
import * as HeadersUtility from "../../Common/HeadersUtility";
|
||||
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
||||
import { createDocument } from "../../Common/dataAccess/createDocument";
|
||||
import { deleteDocument } from "../../Common/dataAccess/deleteDocument";
|
||||
import { queryDocuments } from "../../Common/dataAccess/queryDocuments";
|
||||
import { readDocument } from "../../Common/dataAccess/readDocument";
|
||||
import { updateDocument } from "../../Common/dataAccess/updateDocument";
|
||||
import editable from "../../Common/EditableUtility";
|
||||
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
||||
import * as HeadersUtility from "../../Common/HeadersUtility";
|
||||
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
@@ -30,6 +33,7 @@ import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||
import * as QueryUtils from "../../Utils/QueryUtils";
|
||||
import { extractPartitionKeyValues } from "../../Utils/QueryUtils";
|
||||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||
import { useDialog } from "../Controls/Dialog";
|
||||
import Explorer from "../Explorer";
|
||||
@@ -79,6 +83,7 @@ export default class DocumentsTab extends TabsBase {
|
||||
private _resourceTokenPartitionKey: string;
|
||||
private _isQueryCopilotSampleContainer: boolean;
|
||||
private queryAbortController: AbortController;
|
||||
private cancelQueryTimeoutID: NodeJS.Timeout;
|
||||
|
||||
constructor(options: ViewModels.DocumentsTabOptions) {
|
||||
super(options);
|
||||
@@ -350,11 +355,11 @@ export default class DocumentsTab extends TabsBase {
|
||||
* Query first page of documents
|
||||
* Select and query first document and display content
|
||||
*/
|
||||
private async autoPopulateContent() {
|
||||
private async autoPopulateContent(applyFilterButtonPressed?: boolean) {
|
||||
// reset iterator
|
||||
this._documentsIterator = this.createIterator();
|
||||
// load documents
|
||||
await this.loadNextPage();
|
||||
await this.loadNextPage(applyFilterButtonPressed);
|
||||
|
||||
// Select first document and load content
|
||||
if (this.documentIds().length > 0) {
|
||||
@@ -391,12 +396,14 @@ export default class DocumentsTab extends TabsBase {
|
||||
return true;
|
||||
};
|
||||
|
||||
public async refreshDocumentsGrid(): Promise<void> {
|
||||
public async refreshDocumentsGrid(applyFilterButtonPressed?: boolean): Promise<void> {
|
||||
// clear documents grid
|
||||
this.documentIds([]);
|
||||
|
||||
try {
|
||||
await this.autoPopulateContent();
|
||||
// reset iterator
|
||||
this._documentsIterator = this.createIterator();
|
||||
// load documents
|
||||
await this.autoPopulateContent(applyFilterButtonPressed);
|
||||
// collapse filter
|
||||
this.appliedFilter(this.filterContent());
|
||||
this.isFilterExpanded(false);
|
||||
@@ -473,7 +480,7 @@ export default class DocumentsTab extends TabsBase {
|
||||
const value: string = this.renderObjectForEditor(savedDocument || {}, null, 4);
|
||||
this.selectedDocumentContent.setBaseline(value);
|
||||
this.initialDocumentContent(value);
|
||||
const partitionKeyValueArray = extractPartitionKey(
|
||||
const partitionKeyValueArray: PartitionKey[] = extractPartitionKeyValues(
|
||||
savedDocument,
|
||||
this.partitionKey as PartitionKeyDefinition,
|
||||
);
|
||||
@@ -524,7 +531,10 @@ export default class DocumentsTab extends TabsBase {
|
||||
const selectedDocumentId = this.selectedDocumentId();
|
||||
const documentContent = JSON.parse(this.selectedDocumentContent());
|
||||
|
||||
const partitionKeyValueArray = extractPartitionKey(documentContent, this.partitionKey as PartitionKeyDefinition);
|
||||
const partitionKeyValueArray: PartitionKey[] = extractPartitionKeyValues(
|
||||
documentContent,
|
||||
this.partitionKey as PartitionKeyDefinition,
|
||||
);
|
||||
selectedDocumentId.partitionKeyValue = partitionKeyValueArray;
|
||||
|
||||
this.isExecutionError(false);
|
||||
@@ -733,9 +743,35 @@ export default class DocumentsTab extends TabsBase {
|
||||
this.initDocumentEditor(documentId, content);
|
||||
}
|
||||
|
||||
public loadNextPage(): Q.Promise<any> {
|
||||
public loadNextPage(applyFilterButtonClicked?: boolean): Q.Promise<any> {
|
||||
this.isExecuting(true);
|
||||
this.isExecutionError(false);
|
||||
let automaticallyCancelQueryAfterTimeout: boolean;
|
||||
if (applyFilterButtonClicked && this.queryTimeoutEnabled()) {
|
||||
const queryTimeout: number = LocalStorageUtility.getEntryNumber(StorageKey.QueryTimeout);
|
||||
automaticallyCancelQueryAfterTimeout = LocalStorageUtility.getEntryBoolean(
|
||||
StorageKey.AutomaticallyCancelQueryAfterTimeout,
|
||||
);
|
||||
const cancelQueryTimeoutID: NodeJS.Timeout = setTimeout(() => {
|
||||
if (this.isExecuting()) {
|
||||
if (automaticallyCancelQueryAfterTimeout) {
|
||||
this.queryAbortController.abort();
|
||||
} else {
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkCancelModalDialog(
|
||||
QueryConstants.CancelQueryTitle,
|
||||
format(QueryConstants.CancelQuerySubTextTemplate, QueryConstants.CancelQueryTimeoutThresholdReached),
|
||||
"Yes",
|
||||
() => this.queryAbortController.abort(),
|
||||
"No",
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
}, queryTimeout);
|
||||
this.cancelQueryTimeoutID = cancelQueryTimeoutID;
|
||||
}
|
||||
return this._loadNextPageInternal()
|
||||
.then(
|
||||
(documentsIdsResponse = []) => {
|
||||
@@ -791,7 +827,15 @@ export default class DocumentsTab extends TabsBase {
|
||||
}
|
||||
},
|
||||
)
|
||||
.finally(() => this.isExecuting(false));
|
||||
.finally(() => {
|
||||
this.isExecuting(false);
|
||||
if (applyFilterButtonClicked && this.queryTimeoutEnabled()) {
|
||||
clearTimeout(this.cancelQueryTimeoutID);
|
||||
if (!automaticallyCancelQueryAfterTimeout) {
|
||||
useDialog.getState().closeDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public onLoadMoreKeyInput = (source: any, event: KeyboardEvent): void => {
|
||||
@@ -969,4 +1013,8 @@ export default class DocumentsTab extends TabsBase {
|
||||
useSelectedNode.getState().isQueryCopilotCollectionSelected(),
|
||||
};
|
||||
}
|
||||
|
||||
private queryTimeoutEnabled(): boolean {
|
||||
return !this.isPreferredApiMongoDB && LocalStorageUtility.getEntryBoolean(StorageKey.QueryTimeoutEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { extractPartitionKey, PartitionKeyDefinition } from "@azure/cosmos";
|
||||
import { PartitionKey, PartitionKeyDefinition } from "@azure/cosmos";
|
||||
import { extractPartitionKeyValues } from "Utils/QueryUtils";
|
||||
import * as ko from "knockout";
|
||||
import Q from "q";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
@@ -88,7 +89,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
|
||||
)
|
||||
.then(
|
||||
(savedDocument: any) => {
|
||||
let partitionKeyArray = extractPartitionKey(
|
||||
const partitionKeyArray: PartitionKey[] = extractPartitionKeyValues(
|
||||
savedDocument,
|
||||
this._getPartitionKeyDefinition() as PartitionKeyDefinition,
|
||||
);
|
||||
@@ -150,7 +151,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
|
||||
|
||||
this.documentIds().forEach((documentId: DocumentId) => {
|
||||
if (documentId.rid === updatedDocument._rid) {
|
||||
const partitionKeyArray = extractPartitionKey(
|
||||
const partitionKeyArray: PartitionKey[] = extractPartitionKeyValues(
|
||||
updatedDocument,
|
||||
this._getPartitionKeyDefinition() as PartitionKeyDefinition,
|
||||
);
|
||||
@@ -289,7 +290,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
|
||||
}
|
||||
|
||||
private _hasShardKeySpecified(document: any): boolean {
|
||||
return Boolean(extractPartitionKey(document, this._getPartitionKeyDefinition() as PartitionKeyDefinition));
|
||||
return Boolean(extractPartitionKeyValues(document, this._getPartitionKeyDefinition() as PartitionKeyDefinition));
|
||||
}
|
||||
|
||||
private _getPartitionKeyDefinition(): DataModels.PartitionKey {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { FeedOptions } from "@azure/cosmos";
|
||||
import { useDialog } from "Explorer/Controls/Dialog";
|
||||
import { OnExecuteQueryClick } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
|
||||
import { QueryCopilotResults } from "Explorer/QueryCopilot/Shared/QueryCopilotResults";
|
||||
import { QueryCopilotSidebar } from "Explorer/QueryCopilot/V2/Sidebar/QueryCopilotSidebar";
|
||||
import { QueryResultSection } from "Explorer/Tabs/QueryTab/QueryResultSection";
|
||||
import { QueryConstants } from "Shared/Constants";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import { QueryCopilotState, useQueryCopilot } from "hooks/useQueryCopilot";
|
||||
import React, { Fragment } from "react";
|
||||
import SplitterLayout from "react-splitter-layout";
|
||||
import "react-splitter-layout/lib/index.css";
|
||||
import { format } from "react-string-format";
|
||||
import LaunchCopilot from "../../../../images/CopilotTabIcon.svg";
|
||||
import CancelQueryIcon from "../../../../images/Entity_cancel.svg";
|
||||
import ExecuteQueryIcon from "../../../../images/ExecuteQuery.svg";
|
||||
@@ -80,6 +84,7 @@ interface IQueryTabStates {
|
||||
isExecuting: boolean;
|
||||
showCopilotSidebar: boolean;
|
||||
queryCopilotGeneratedQuery: string;
|
||||
cancelQueryTimeoutID: NodeJS.Timeout;
|
||||
}
|
||||
|
||||
export default class QueryTabComponent extends React.Component<IQueryTabComponentProps, IQueryTabStates> {
|
||||
@@ -107,13 +112,13 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
isExecuting: false,
|
||||
showCopilotSidebar: useQueryCopilot.getState().showCopilotSidebar,
|
||||
queryCopilotGeneratedQuery: useQueryCopilot.getState().query,
|
||||
cancelQueryTimeoutID: undefined,
|
||||
};
|
||||
this.isCloseClicked = false;
|
||||
this.splitterId = this.props.tabId + "_splitter";
|
||||
this.queryEditorId = `queryeditor${this.props.tabId}`;
|
||||
this.isPreferredApiMongoDB = this.props.isPreferredApiMongoDB;
|
||||
this.isCopilotTabActive = QueryCopilotSampleDatabaseId === this.props.collection.databaseId;
|
||||
|
||||
this.executeQueryButton = {
|
||||
enabled: !!this.state.sqlQueryEditorContent && this.state.sqlQueryEditorContent.length > 0,
|
||||
visible: true,
|
||||
@@ -250,6 +255,34 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
this.setState({
|
||||
isExecuting: true,
|
||||
});
|
||||
let automaticallyCancelQueryAfterTimeout: boolean;
|
||||
if (this.queryTimeoutEnabled()) {
|
||||
const queryTimeout: number = LocalStorageUtility.getEntryNumber(StorageKey.QueryTimeout);
|
||||
automaticallyCancelQueryAfterTimeout = LocalStorageUtility.getEntryBoolean(
|
||||
StorageKey.AutomaticallyCancelQueryAfterTimeout,
|
||||
);
|
||||
const cancelQueryTimeoutID: NodeJS.Timeout = setTimeout(() => {
|
||||
if (this.state.isExecuting) {
|
||||
if (automaticallyCancelQueryAfterTimeout) {
|
||||
this.queryAbortController.abort();
|
||||
} else {
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkCancelModalDialog(
|
||||
QueryConstants.CancelQueryTitle,
|
||||
format(QueryConstants.CancelQuerySubTextTemplate, QueryConstants.CancelQueryTimeoutThresholdReached),
|
||||
"Yes",
|
||||
() => this.queryAbortController.abort(),
|
||||
"No",
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
}, queryTimeout);
|
||||
this.setState({
|
||||
cancelQueryTimeoutID,
|
||||
});
|
||||
}
|
||||
useCommandBar.getState().setContextButtons(this.getTabsButtons());
|
||||
|
||||
try {
|
||||
@@ -273,7 +306,14 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
this.props.tabsBaseInstance.isExecuting(false);
|
||||
this.setState({
|
||||
isExecuting: false,
|
||||
cancelQueryTimeoutID: undefined,
|
||||
});
|
||||
if (this.queryTimeoutEnabled()) {
|
||||
clearTimeout(this.state.cancelQueryTimeoutID);
|
||||
if (!automaticallyCancelQueryAfterTimeout) {
|
||||
useDialog.getState().closeDialog();
|
||||
}
|
||||
}
|
||||
this.togglesOnFocus();
|
||||
useCommandBar.getState().setContextButtons(this.getTabsButtons());
|
||||
}
|
||||
@@ -405,6 +445,10 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
return this.state.sqlQueryEditorContent;
|
||||
}
|
||||
|
||||
private queryTimeoutEnabled(): boolean {
|
||||
return !this.isPreferredApiMongoDB && LocalStorageUtility.getEntryBoolean(StorageKey.QueryTimeoutEnabled);
|
||||
}
|
||||
|
||||
private unsubscribeCopilotSidebar: () => void;
|
||||
|
||||
componentDidMount(): void {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { extractPartitionKey } from "@azure/cosmos";
|
||||
import { extractPartitionKeyValues } from "Utils/QueryUtils";
|
||||
import * as ko from "knockout";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { readDocument } from "../../Common/dataAccess/readDocument";
|
||||
@@ -42,7 +42,7 @@ export default class ConflictId {
|
||||
}
|
||||
this.partitionKeyProperty = container && container.partitionKeyProperty;
|
||||
this.partitionKey = container && container.partitionKey;
|
||||
this.partitionKeyValue = extractPartitionKey(this.parsedContent, this.partitionKey as any);
|
||||
this.partitionKeyValue = extractPartitionKeyValues(this.parsedContent, this.partitionKey as any);
|
||||
this.stringPartitionKeyValue = this.getPartitionKeyValueAsString();
|
||||
this.id = ko.observable(data.id);
|
||||
this.isDirty = ko.observable(false);
|
||||
|
||||
@@ -208,3 +208,9 @@ export class FreeTierLimits {
|
||||
public static RU: number = 1000;
|
||||
public static Storage: number = 25;
|
||||
}
|
||||
|
||||
export class QueryConstants {
|
||||
public static readonly CancelQueryTitle: string = "Cancel query";
|
||||
public static readonly CancelQuerySubTextTemplate: string = "{0} Do you want to cancel this query?";
|
||||
public static readonly CancelQueryTimeoutThresholdReached: string = "The query timeout threshold has been reached.";
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { PriorityLevel } from "@azure/cosmos";
|
||||
import * as Constants from "../Common/Constants";
|
||||
import { LocalStorageUtility, StorageKey } from "./StorageUtility";
|
||||
|
||||
@@ -6,7 +7,7 @@ export const createDefaultSettings = () => {
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.CustomItemPerPage, Constants.Queries.itemsPerPage);
|
||||
LocalStorageUtility.setEntryString(StorageKey.IsCrossPartitionQueryEnabled, "true");
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.MaxDegreeOfParellism, Constants.Queries.DefaultMaxDegreeOfParallelism);
|
||||
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, Constants.PriorityLevel.Default);
|
||||
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, PriorityLevel.Low);
|
||||
};
|
||||
|
||||
export const hasSettingsDefined = (): boolean => {
|
||||
@@ -19,6 +20,6 @@ export const hasSettingsDefined = (): boolean => {
|
||||
|
||||
export const ensurePriorityLevel = () => {
|
||||
if (!LocalStorageUtility.hasItem(StorageKey.PriorityLevel)) {
|
||||
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, Constants.PriorityLevel.Default);
|
||||
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, PriorityLevel.Low);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,6 +4,9 @@ import * as SessionStorageUtility from "./SessionStorageUtility";
|
||||
export { LocalStorageUtility, SessionStorageUtility };
|
||||
export enum StorageKey {
|
||||
ActualItemPerPage,
|
||||
QueryTimeoutEnabled,
|
||||
QueryTimeout,
|
||||
AutomaticallyCancelQueryAfterTimeout,
|
||||
ContainerPaginationEnabled,
|
||||
CustomItemPerPage,
|
||||
DatabaseAccountId,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as PriorityBasedExecutionUtils from "./PriorityBasedExecutionUtils";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import { PriorityLevel } from "../Common/Constants";
|
||||
import * as Cosmos from "@azure/cosmos";
|
||||
import { PriorityLevel } from "@azure/cosmos";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import * as PriorityBasedExecutionUtils from "./PriorityBasedExecutionUtils";
|
||||
|
||||
describe("Priority execution utility", () => {
|
||||
it("check default priority level is Low", () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as Cosmos from "@azure/cosmos";
|
||||
import { Constants, PriorityLevel } from "@azure/cosmos";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import { PriorityLevel } from "../Common/Constants";
|
||||
import { userContext } from "../UserContext";
|
||||
|
||||
export function isFeatureEnabled(): boolean {
|
||||
@@ -21,18 +21,18 @@ export function isRelevantRequest(requestContext: Cosmos.RequestContext): boolea
|
||||
}
|
||||
|
||||
export function getPriorityLevel(): PriorityLevel {
|
||||
const priorityLevel = LocalStorageUtility.getEntryString(StorageKey.PriorityLevel);
|
||||
if (priorityLevel && Object.values(PriorityLevel).includes(priorityLevel)) {
|
||||
const priorityLevel: string = LocalStorageUtility.getEntryString(StorageKey.PriorityLevel);
|
||||
if (priorityLevel) {
|
||||
return priorityLevel as PriorityLevel;
|
||||
} else {
|
||||
return PriorityLevel.Default;
|
||||
return PriorityLevel.Low;
|
||||
}
|
||||
}
|
||||
|
||||
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, next) => {
|
||||
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, undefined, next) => {
|
||||
if (isRelevantRequest(requestContext)) {
|
||||
const priorityLevel: PriorityLevel = getPriorityLevel();
|
||||
requestContext.headers["x-ms-cosmos-priority-level"] = priorityLevel as string;
|
||||
requestContext.headers[Constants.HttpHeaders.PriorityLevel] = priorityLevel;
|
||||
}
|
||||
return next(requestContext);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { PartitionKey, PartitionKeyDefinition, PartitionKeyKind } from "@azure/cosmos";
|
||||
import * as Q from "q";
|
||||
import * as sinon from "sinon";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import * as QueryUtils from "./QueryUtils";
|
||||
import { extractPartitionKeyValues } from "./QueryUtils";
|
||||
|
||||
describe("Query Utils", () => {
|
||||
const generatePartitionKeyForPath = (path: string): DataModels.PartitionKey => {
|
||||
@@ -94,4 +96,69 @@ describe("Query Utils", () => {
|
||||
expect(queryStub.getCall(0).args[0]).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractPartitionKey", () => {
|
||||
const documentContent = {
|
||||
"Volcano Name": "Adams",
|
||||
Country: "United States",
|
||||
Region: "US-Washington",
|
||||
Location: {
|
||||
type: "Point",
|
||||
coordinates: [-121.49, 46.206],
|
||||
},
|
||||
Elevation: 3742,
|
||||
Type: "Stratovolcano",
|
||||
Status: "Tephrochronology",
|
||||
"Last Known Eruption": "Last known eruption from A.D. 1-1499, inclusive",
|
||||
id: "9e3c494e-8367-3f50-1f56-8c6fcb961363",
|
||||
_rid: "xzo0AJRYUxUFAAAAAAAAAA==",
|
||||
_self: "dbs/xzo0AA==/colls/xzo0AJRYUxU=/docs/xzo0AJRYUxUFAAAAAAAAAA==/",
|
||||
_etag: '"ce00fa43-0000-0100-0000-652840440000"',
|
||||
_attachments: "attachments/",
|
||||
_ts: 1697136708,
|
||||
};
|
||||
|
||||
it("should extract single partition key value", () => {
|
||||
const singlePartitionKeyDefinition: PartitionKeyDefinition = {
|
||||
kind: PartitionKeyKind.Hash,
|
||||
paths: ["/Elevation"],
|
||||
};
|
||||
|
||||
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(
|
||||
documentContent,
|
||||
singlePartitionKeyDefinition,
|
||||
);
|
||||
expect(partitionKeyValues.length).toBe(1);
|
||||
expect(partitionKeyValues[0]).toEqual(3742);
|
||||
});
|
||||
|
||||
it("should extract two partition key values", () => {
|
||||
const multiPartitionKeyDefinition: PartitionKeyDefinition = {
|
||||
kind: PartitionKeyKind.MultiHash,
|
||||
paths: ["/Type", "/Status"],
|
||||
};
|
||||
const expectedPartitionKeyValues: string[] = ["Stratovolcano", "Tephrochronology"];
|
||||
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(
|
||||
documentContent,
|
||||
multiPartitionKeyDefinition,
|
||||
);
|
||||
expect(partitionKeyValues.length).toBe(2);
|
||||
expect(expectedPartitionKeyValues).toContain(documentContent["Type"]);
|
||||
expect(expectedPartitionKeyValues).toContain(documentContent["Status"]);
|
||||
});
|
||||
|
||||
it("should extract no partition key values", () => {
|
||||
const singlePartitionKeyDefinition: PartitionKeyDefinition = {
|
||||
kind: PartitionKeyKind.Hash,
|
||||
paths: ["/InvalidPartitionKeyPath"],
|
||||
};
|
||||
|
||||
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(
|
||||
documentContent,
|
||||
singlePartitionKeyDefinition,
|
||||
);
|
||||
|
||||
expect(partitionKeyValues.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { PartitionKey, PartitionKeyDefinition } from "@azure/cosmos";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
|
||||
@@ -82,3 +83,22 @@ export const queryPagesUntilContentPresent = async (
|
||||
|
||||
return await doRequest(firstItemIndex);
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
export const extractPartitionKeyValues = (
|
||||
documentContent: any,
|
||||
partitionKeyDefinition: PartitionKeyDefinition,
|
||||
): PartitionKey[] => {
|
||||
if (!partitionKeyDefinition.paths || partitionKeyDefinition.paths.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const partitionKeyValues: PartitionKey[] = [];
|
||||
partitionKeyDefinition.paths.forEach((partitionKeyPath: string) => {
|
||||
const partitionKeyPathWithoutSlash: string = partitionKeyPath.substring(1);
|
||||
if (documentContent[partitionKeyPathWithoutSlash]) {
|
||||
partitionKeyValues.push(documentContent[partitionKeyPathWithoutSlash]);
|
||||
}
|
||||
});
|
||||
return partitionKeyValues;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user