mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-23 02:41:39 +00:00
Compare commits
16 Commits
users/lang
...
unit-tests
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f4a4e5c4c | ||
|
|
1b64827c24 | ||
|
|
a6ae784a45 | ||
|
|
7458107efd | ||
|
|
64533b445f | ||
|
|
d7bdd0032e | ||
|
|
372ac6921f | ||
|
|
c6eda097fc | ||
|
|
05d02f08fa | ||
|
|
ab4f02f74a | ||
|
|
0fc6647627 | ||
|
|
c5ed537109 | ||
|
|
db322ccb59 | ||
|
|
2d7631c358 | ||
|
|
e401c88df6 | ||
|
|
f14b574527 |
199
package-lock.json
generated
199
package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@azure/arm-cosmosdb": "9.1.0",
|
||||
"@azure/cosmos": "4.2.0-beta.1",
|
||||
"@azure/cosmos": "4.3.0",
|
||||
"@azure/cosmos-language-service": "0.0.5",
|
||||
"@azure/identity": "4.5.0",
|
||||
"@azure/msal-browser": "2.14.2",
|
||||
@@ -290,57 +290,69 @@
|
||||
"version": "2.6.2",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline": {
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.0.tgz",
|
||||
"integrity": "sha512-QSoGUp4Eq/gohEFNJaUOwTN7BCc2nHTjjbm75JT0aD7W65PWM1H/tItz0GsABn22uaKyGxiMhWQLt2r+FGU89Q==",
|
||||
"node_modules/@azure/core-http-compat": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.0.tgz",
|
||||
"integrity": "sha512-qLQujmUypBBG0gxHd0j6/Jdmul6ttl24c8WGiLXIk7IHXdBlfoBqW27hyz3Xn6xbfdyVSarl1Ttbk0AwnZBYCw==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-auth": "^1.8.0",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.11.0",
|
||||
"@azure/core-client": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-lro": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz",
|
||||
"integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-util": "^1.2.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline/node_modules/agent-base": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
|
||||
"integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
|
||||
"node_modules/@azure/core-lro/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/@azure/core-paging": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz",
|
||||
"integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline/node_modules/http-proxy-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
|
||||
"node_modules/@azure/core-paging/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.20.0.tgz",
|
||||
"integrity": "sha512-ASoP8uqZBS3H/8N8at/XwFr6vYrRP3syTK0EUjDXQy0Y1/AUS+QeIRThKmTNJO2RggvBBxaXDPM7YoIwDGeA0g==",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.0",
|
||||
"debug": "^4.3.4"
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-auth": "^1.8.0",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.11.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"@typespec/ts-http-runtime": "^0.2.2",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline/node_modules/https-proxy-agent": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
|
||||
"integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.0.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline/node_modules/tslib": {
|
||||
@@ -379,15 +391,16 @@
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/@azure/cosmos": {
|
||||
"version": "4.2.0-beta.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-4.2.0-beta.1.tgz",
|
||||
"integrity": "sha512-mREONehm1DxjEKXGaNU6Wmpf9Ckb9IrhKFXhDFVs45pxmoEb3y2s/Ub0owuFmqlphpcS1zgtYQn5exn+lwnJuQ==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-4.3.0.tgz",
|
||||
"integrity": "sha512-0Ls3l1uWBBSphx6YRhnM+w7rSvq8qVugBCdO6kSiNuRYXEf6+YWLjbzz4e7L2kkz/6ScFdZIOJYP+XtkiRYOhA==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-auth": "^1.7.1",
|
||||
"@azure/core-rest-pipeline": "^1.15.1",
|
||||
"@azure/core-tracing": "^1.1.1",
|
||||
"@azure/core-util": "^1.8.1",
|
||||
"@azure/keyvault-keys": "^4.8.0",
|
||||
"fast-json-stable-stringify": "^2.1.0",
|
||||
"jsbi": "^4.3.0",
|
||||
"priorityqueuejs": "^2.0.0",
|
||||
@@ -492,14 +505,66 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/@azure/logger": {
|
||||
"version": "1.0.4",
|
||||
"license": "MIT",
|
||||
"node_modules/@azure/keyvault-common": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/keyvault-common/-/keyvault-common-2.0.0.tgz",
|
||||
"integrity": "sha512-wRLVaroQtOqfg60cxkzUkGKrKMsCP6uYXAOomOIysSMyt1/YM0eUn9LqieAWM8DLcU4+07Fio2YGpPeqUbpP9w==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-client": "^1.5.0",
|
||||
"@azure/core-rest-pipeline": "^1.8.0",
|
||||
"@azure/core-tracing": "^1.0.0",
|
||||
"@azure/core-util": "^1.10.0",
|
||||
"@azure/logger": "^1.1.4",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/keyvault-common/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/@azure/keyvault-keys": {
|
||||
"version": "4.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.9.0.tgz",
|
||||
"integrity": "sha512-ZBP07+K4Pj3kS4TF4XdkqFcspWwBHry3vJSOFM5k5ZABvf7JfiMonvaFk2nBF6xjlEbMpz5PE1g45iTMme0raQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-client": "^1.5.0",
|
||||
"@azure/core-http-compat": "^2.0.1",
|
||||
"@azure/core-lro": "^2.2.0",
|
||||
"@azure/core-paging": "^1.1.1",
|
||||
"@azure/core-rest-pipeline": "^1.8.1",
|
||||
"@azure/core-tracing": "^1.0.0",
|
||||
"@azure/core-util": "^1.0.0",
|
||||
"@azure/keyvault-common": "^2.0.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/keyvault-keys/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/@azure/logger": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.2.0.tgz",
|
||||
"integrity": "sha512-0hKEzLhpw+ZTAfNJyRrn6s+V0nDWzXk9OjBr2TiGIu0OfMr5s2V4FpKLTAK3Ca5r5OKLbf4hkOGDPyiRjie/jA==",
|
||||
"dependencies": {
|
||||
"@typespec/ts-http-runtime": "^0.2.2",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/logger/node_modules/tslib": {
|
||||
@@ -13074,6 +13139,56 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typespec/ts-http-runtime": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.2.2.tgz",
|
||||
"integrity": "sha512-Gz/Sm64+Sq/vklJu1tt9t+4R2lvnud8NbTD/ZfpZtMiUX7YeVpCA8j6NSW8ptwcoLL+NmYANwqP8DV0q/bwl2w==",
|
||||
"dependencies": {
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.0",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typespec/ts-http-runtime/node_modules/agent-base": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
|
||||
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@typespec/ts-http-runtime/node_modules/http-proxy-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@typespec/ts-http-runtime/node_modules/https-proxy-agent": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@typespec/ts-http-runtime/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/@ungap/url-search-params": {
|
||||
"version": "0.2.2",
|
||||
"license": "ISC"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@azure/arm-cosmosdb": "9.1.0",
|
||||
"@azure/cosmos": "4.2.0-beta.1",
|
||||
"@azure/cosmos": "4.3.0",
|
||||
"@azure/cosmos-language-service": "0.0.5",
|
||||
"@azure/identity": "4.5.0",
|
||||
"@azure/msal-browser": "2.14.2",
|
||||
|
||||
6
preview/package-lock.json
generated
6
preview/package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@azure/arm-cosmosdb": "9.1.0",
|
||||
"@azure/cosmos": "4.2.0-beta.1",
|
||||
"@azure/cosmos": "4.3.0",
|
||||
"@azure/cosmos-language-service": "0.0.5",
|
||||
"@azure/identity": "4.5.0",
|
||||
"@azure/msal-browser": "2.14.2",
|
||||
@@ -377,8 +377,8 @@
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/@azure/cosmos": {
|
||||
"version": "4.2.0-beta.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-4.2.0-beta.1.tgz",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-4.3.0.tgz",
|
||||
"integrity": "sha512-mREONehm1DxjEKXGaNU6Wmpf9Ckb9IrhKFXhDFVs45pxmoEb3y2s/Ub0owuFmqlphpcS1zgtYQn5exn+lwnJuQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { QueryOperationOptions } from "@azure/cosmos";
|
||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
import * as Constants from "../Common/Constants";
|
||||
import { QueryResults } from "../Contracts/ViewModels";
|
||||
@@ -14,18 +13,14 @@ interface QueryResponse {
|
||||
}
|
||||
|
||||
export interface MinimalQueryIterator {
|
||||
fetchNext: (queryOperationOptions?: QueryOperationOptions) => Promise<QueryResponse>;
|
||||
fetchNext: () => Promise<QueryResponse>;
|
||||
}
|
||||
|
||||
// Pick<QueryIterator<any>, "fetchNext">;
|
||||
|
||||
export function nextPage(
|
||||
documentsIterator: MinimalQueryIterator,
|
||||
firstItemIndex: number,
|
||||
queryOperationOptions?: QueryOperationOptions,
|
||||
): Promise<QueryResults> {
|
||||
export function nextPage(documentsIterator: MinimalQueryIterator, firstItemIndex: number): Promise<QueryResults> {
|
||||
TelemetryProcessor.traceStart(Action.ExecuteQuery);
|
||||
return documentsIterator.fetchNext(queryOperationOptions).then((response) => {
|
||||
return documentsIterator.fetchNext().then((response) => {
|
||||
TelemetryProcessor.traceSuccess(Action.ExecuteQuery, { dataExplorerArea: Constants.Areas.Tab });
|
||||
const documents = response.resources;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { monaco } from "Explorer/LazyMonaco";
|
||||
import { getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility";
|
||||
|
||||
export enum QueryErrorSeverity {
|
||||
Error = "Error",
|
||||
@@ -103,20 +102,9 @@ export interface ErrorEnrichment {
|
||||
learnMoreUrl?: string;
|
||||
}
|
||||
|
||||
const REPLACEMENT_MESSAGES: Record<string, (original: string) => string> = {
|
||||
OPERATION_RU_LIMIT_EXCEEDED: (original) => {
|
||||
if (ruThresholdEnabled()) {
|
||||
const threshold = getRUThreshold();
|
||||
return `Query exceeded the Request Unit (RU) limit of ${threshold} RUs. You can change this limit in Data Explorer settings.`;
|
||||
}
|
||||
return original;
|
||||
},
|
||||
};
|
||||
const REPLACEMENT_MESSAGES: Record<string, (original: string) => string> = {};
|
||||
|
||||
const HELP_LINKS: Record<string, string> = {
|
||||
OPERATION_RU_LIMIT_EXCEEDED:
|
||||
"https://learn.microsoft.com/en-us/azure/cosmos-db/data-explorer#configure-request-unit-threshold",
|
||||
};
|
||||
const HELP_LINKS: Record<string, string> = {};
|
||||
|
||||
export default class QueryError {
|
||||
message: string;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
exports[`getCommonQueryOptions builds the correct default options objects 1`] = `
|
||||
{
|
||||
"disableNonStreamingOrderByQuery": true,
|
||||
"enableQueryControl": false,
|
||||
"enableScanInQuery": true,
|
||||
"forceQueryPlan": true,
|
||||
"maxDegreeOfParallelism": 0,
|
||||
@@ -14,6 +15,7 @@ exports[`getCommonQueryOptions builds the correct default options objects 1`] =
|
||||
exports[`getCommonQueryOptions reads from localStorage 1`] = `
|
||||
{
|
||||
"disableNonStreamingOrderByQuery": true,
|
||||
"enableQueryControl": false,
|
||||
"enableScanInQuery": true,
|
||||
"forceQueryPlan": true,
|
||||
"maxDegreeOfParallelism": 17,
|
||||
|
||||
@@ -26,6 +26,7 @@ export const getCommonQueryOptions = (options: FeedOptions): FeedOptions => {
|
||||
options.maxItemCount ||
|
||||
(storedItemPerPageSetting !== undefined && storedItemPerPageSetting) ||
|
||||
Queries.itemsPerPage;
|
||||
options.enableQueryControl = LocalStorageUtility.getEntryBoolean(StorageKey.QueryControlEnabled);
|
||||
options.maxDegreeOfParallelism = LocalStorageUtility.getEntryNumber(StorageKey.MaxDegreeOfParellism);
|
||||
options.disableNonStreamingOrderByQuery = !isVectorSearchEnabled();
|
||||
return options;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { QueryOperationOptions } from "@azure/cosmos";
|
||||
import { QueryResults } from "../../Contracts/ViewModels";
|
||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
import { getEntityName } from "../DocumentUtility";
|
||||
@@ -9,13 +8,12 @@ export const queryDocumentsPage = async (
|
||||
resourceName: string,
|
||||
documentsIterator: MinimalQueryIterator,
|
||||
firstItemIndex: number,
|
||||
queryOperationOptions?: QueryOperationOptions,
|
||||
): Promise<QueryResults> => {
|
||||
const entityName = getEntityName();
|
||||
const clearMessage = logConsoleProgress(`Querying ${entityName} for container ${resourceName}`);
|
||||
|
||||
try {
|
||||
const result: QueryResults = await nextPage(documentsIterator, firstItemIndex, queryOperationOptions);
|
||||
const result: QueryResults = await nextPage(documentsIterator, firstItemIndex);
|
||||
const itemCount = (result.documents && result.documents.length) || 0;
|
||||
logConsoleInfo(`Successfully fetched ${itemCount} ${entityName} for container ${resourceName}`);
|
||||
return result;
|
||||
|
||||
@@ -126,12 +126,5 @@ async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Co
|
||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
||||
}
|
||||
|
||||
// TO DO: Remove when we get RP API Spec with materializedViews
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
return rpResponse?.value?.map((collection: any) => {
|
||||
const collectionDataModel: DataModels.Collection = collection.properties?.resource as DataModels.Collection;
|
||||
collectionDataModel.materializedViews = collection.properties?.resource?.materializedViews;
|
||||
collectionDataModel.materializedViewDefinition = collection.properties?.resource?.materializedViewDefinition;
|
||||
return collectionDataModel;
|
||||
});
|
||||
return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ export enum PaneKind {
|
||||
GlobalSettings,
|
||||
AdHocAccess,
|
||||
SwitchDirectory,
|
||||
QuickStart,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { FabricMessageTypes } from "./FabricMessageTypes";
|
||||
import { MessageTypes } from "./MessageTypes";
|
||||
|
||||
// This is the current version of these messages
|
||||
export const DATA_EXPLORER_RPC_VERSION = "3";
|
||||
@@ -20,22 +19,9 @@ export type DataExploreMessageV3 =
|
||||
type: FabricMessageTypes.GetAllResourceTokens;
|
||||
id: string;
|
||||
}
|
||||
| {
|
||||
type: FabricMessageTypes.GetAccessToken;
|
||||
id: string;
|
||||
}
|
||||
| {
|
||||
type: MessageTypes.TelemetryInfo;
|
||||
data: {
|
||||
action: string;
|
||||
actionModifier: string;
|
||||
data: unknown;
|
||||
timestamp: number;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: FabricMessageTypes.OpenSettings;
|
||||
params: [{ settingsId?: "About" | "Connection" }];
|
||||
settingsId: string;
|
||||
};
|
||||
export interface GetCosmosTokenMessageOptions {
|
||||
verb: "connect" | "delete" | "get" | "head" | "options" | "patch" | "post" | "put" | "trace";
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface ArmEntity {
|
||||
type: string;
|
||||
kind: string;
|
||||
tags?: Tags;
|
||||
resourceGroup?: string;
|
||||
}
|
||||
|
||||
export interface DatabaseAccount extends ArmEntity {
|
||||
@@ -388,7 +389,7 @@ export interface VectorEmbeddingPolicy {
|
||||
}
|
||||
|
||||
export interface VectorEmbedding {
|
||||
dataType: "float16" | "float32" | "uint8" | "int8";
|
||||
dataType: "float32" | "uint8" | "int8";
|
||||
dimensions: number;
|
||||
distanceFunction: "euclidean" | "cosine" | "dotproduct";
|
||||
path: string;
|
||||
|
||||
@@ -50,6 +50,7 @@ export interface QueryResults extends QueryResultsMetadata {
|
||||
roundTrips?: number;
|
||||
headers?: any;
|
||||
queryMetrics?: QueryMetrics;
|
||||
ruThresholdExceeded?: boolean;
|
||||
}
|
||||
|
||||
export interface Button {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from "Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent";
|
||||
import { useDatabases } from "Explorer/useDatabases";
|
||||
import { isFabricNative } from "Platform/Fabric/FabricUtil";
|
||||
import { isFullTextSearchEnabled, isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
||||
import { isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
||||
import { isRunningOnPublicCloud } from "Utils/CloudUtils";
|
||||
import * as React from "react";
|
||||
import DiscardIcon from "../../../../images/discard.svg";
|
||||
@@ -188,7 +188,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
this.isGlobalSecondaryIndex =
|
||||
!!this.collection?.materializedViewDefinition() || !!this.collection?.materializedViews();
|
||||
this.isVectorSearchEnabled = isVectorSearchEnabled() && !hasDatabaseSharedThroughput(this.collection);
|
||||
this.isFullTextSearchEnabled = isFullTextSearchEnabled() && !hasDatabaseSharedThroughput(this.collection);
|
||||
this.isFullTextSearchEnabled = userContext.apiType === "SQL";
|
||||
|
||||
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
|
||||
this.throughputBucketsEnabled = userContext.throughputBucketsEnabled;
|
||||
@@ -1091,6 +1091,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
currentOffer: this.collection.offer(),
|
||||
autopilotThroughput: this.state.isAutoPilotSelected ? this.state.autoPilotThroughput : undefined,
|
||||
manualThroughput: this.state.isAutoPilotSelected ? undefined : this.state.throughput,
|
||||
throughputBuckets: this.throughputBucketsEnabled ? this.state.throughputBuckets : undefined,
|
||||
};
|
||||
if (this.hasProvisioningTypeChanged()) {
|
||||
if (this.state.isAutoPilotSelected) {
|
||||
|
||||
@@ -198,6 +198,32 @@ exports[`SettingsComponent renders 1`] = `
|
||||
timeToLiveSecondsBaseline={5}
|
||||
/>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Container Policies"
|
||||
itemKey="ContainerVectorPolicyTab"
|
||||
key="ContainerVectorPolicyTab"
|
||||
style={
|
||||
{
|
||||
"marginTop": 20,
|
||||
}
|
||||
}
|
||||
>
|
||||
<ContainerPolicyComponent
|
||||
fullTextPolicy={{}}
|
||||
fullTextPolicyBaseline={{}}
|
||||
isFullTextSearchEnabled={true}
|
||||
isGlobalSecondaryIndex={true}
|
||||
isVectorSearchEnabled={false}
|
||||
onFullTextPolicyChange={[Function]}
|
||||
onFullTextPolicyDirtyChange={[Function]}
|
||||
onVectorEmbeddingPolicyChange={[Function]}
|
||||
onVectorEmbeddingPolicyDirtyChange={[Function]}
|
||||
resetShouldDiscardContainerPolicyChange={[Function]}
|
||||
shouldDiscardContainerPolicies={false}
|
||||
vectorEmbeddingPolicy={{}}
|
||||
vectorEmbeddingPolicyBaseline={{}}
|
||||
/>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Indexing Policy"
|
||||
itemKey="IndexingPolicyTab"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Text } from "@fluentui/react";
|
||||
import { Stack, Text } from "@fluentui/react";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { InfoTooltip } from "../../../../Common/Tooltip/InfoTooltip";
|
||||
import * as SharedConstants from "../../../../Shared/Constants";
|
||||
@@ -54,6 +54,7 @@ export const CostEstimateText: FunctionComponent<CostEstimateTextProps> = ({
|
||||
|
||||
if (isAutoscale) {
|
||||
return (
|
||||
<Stack style={{ marginBottom: 6 }}>
|
||||
<Text variant="small">
|
||||
{estimatedMonthlyCost} ({currency}){iconWithEstimatedCostDisclaimer}:{" "}
|
||||
<b>
|
||||
@@ -63,10 +64,12 @@ export const CostEstimateText: FunctionComponent<CostEstimateTextProps> = ({
|
||||
({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits / 10} - {requestUnits}{" "}
|
||||
RU/s, {currencySign + pricePerRu}/RU)
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack style={{ marginBottom: 8 }}>
|
||||
<Text variant="small">
|
||||
Estimated cost ({currency}){iconWithEstimatedCostDisclaimer}:{" "}
|
||||
<b>
|
||||
@@ -77,5 +80,6 @@ export const CostEstimateText: FunctionComponent<CostEstimateTextProps> = ({
|
||||
({numberOfRegions + (numberOfRegions === 1 ? " region" : " regions")}, {requestUnits}RU/s,{" "}
|
||||
{currencySign + pricePerRu}/RU)
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Checkbox, DirectionalHint, Link, Stack, Text, TextField, TooltipHost } from "@fluentui/react";
|
||||
import { Checkbox, DirectionalHint, Link, Separator, Stack, Text, TextField, TooltipHost } from "@fluentui/react";
|
||||
import { getWorkloadType } from "Common/DatabaseAccountUtility";
|
||||
import { CostEstimateText } from "Explorer/Controls/ThroughputInput/CostEstimateText/CostEstimateText";
|
||||
import { useDatabases } from "Explorer/useDatabases";
|
||||
import React, { FunctionComponent, useEffect, useState } from "react";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
@@ -9,8 +10,8 @@ import { userContext } from "../../../UserContext";
|
||||
import { getCollectionName } from "../../../Utils/APITypeUtils";
|
||||
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
||||
import * as PricingUtils from "../../../Utils/PricingUtils";
|
||||
import { CostEstimateText } from "./CostEstimateText/CostEstimateText";
|
||||
import "./ThroughputInput.less";
|
||||
import { isFabricNative } from "../../../Platform/Fabric/FabricUtil";
|
||||
|
||||
export interface ThroughputInputProps {
|
||||
isDatabase: boolean;
|
||||
@@ -43,7 +44,8 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
if (
|
||||
isFreeTier ||
|
||||
isQuickstart ||
|
||||
[Constants.WorkloadType.Learning, Constants.WorkloadType.DevelopmentTesting].includes(workloadType)
|
||||
[Constants.WorkloadType.Learning, Constants.WorkloadType.DevelopmentTesting].includes(workloadType) ||
|
||||
isFabricNative()
|
||||
) {
|
||||
defaultThroughput = AutoPilotUtils.autoPilotThroughput1K;
|
||||
} else if (workloadType === Constants.WorkloadType.Production) {
|
||||
@@ -230,36 +232,65 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
</div>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{isAutoscaleSelected && (
|
||||
<Stack className="throughputInputSpacing">
|
||||
<Text variant="small" aria-label="capacity calculator of azure cosmos db">
|
||||
Estimate your required RU/s with{" "}
|
||||
<Link
|
||||
className="underlinedLink outlineNone"
|
||||
target="_blank"
|
||||
href="https://cosmos.azure.com/capacitycalculator/"
|
||||
aria-label="capacity calculator of azure cosmos db"
|
||||
<Text style={{ marginTop: -2, fontSize: 12 }}>
|
||||
Your container throughput will automatically scale up to the maximum value you select, from a minimum of 10%
|
||||
of that value.
|
||||
</Text>
|
||||
<Stack horizontal verticalAlign="end" tokens={{ childrenGap: 8 }}>
|
||||
<Stack tokens={{ childrenGap: 4 }}>
|
||||
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600 }}>
|
||||
Minimum RU/s
|
||||
</Text>
|
||||
<InfoTooltip>The minimum RU/s your container will scale to</InfoTooltip>
|
||||
</Stack>
|
||||
<Text
|
||||
style={{
|
||||
fontFamily: "Segoe UI",
|
||||
width: 70,
|
||||
height: 27,
|
||||
border: "none",
|
||||
fontSize: 14,
|
||||
backgroundColor: "transparent",
|
||||
fontWeight: 400,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
capacity calculator
|
||||
</Link>
|
||||
.
|
||||
{Math.round(throughput / 10).toString()}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Text
|
||||
style={{
|
||||
fontFamily: "Segoe UI",
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
paddingBottom: 6,
|
||||
}}
|
||||
>
|
||||
x 10 =
|
||||
</Text>
|
||||
|
||||
<Stack horizontal>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600 }} aria-label="maxRUDescription">
|
||||
{isDatabase ? "Database" : getCollectionName()} Max RU/s
|
||||
<Stack tokens={{ childrenGap: 4 }}>
|
||||
<Stack horizontal verticalAlign="center" tokens={{ childrenGap: 4 }}>
|
||||
<Text variant="small" style={{ lineHeight: "20px", fontWeight: 600 }}>
|
||||
Maximum RU/s
|
||||
</Text>
|
||||
<InfoTooltip>{getAutoScaleTooltip()}</InfoTooltip>
|
||||
</Stack>
|
||||
|
||||
<TextField
|
||||
id="autoscaleRUValueField"
|
||||
type="number"
|
||||
styles={{
|
||||
fieldGroup: { width: 300, height: 27 },
|
||||
field: { fontSize: 12 },
|
||||
fieldGroup: { width: 100, height: 27, flexShrink: 0 },
|
||||
field: { fontSize: 14, fontWeight: 400 },
|
||||
}}
|
||||
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
|
||||
onChange={(_event, newInput?: string) => onThroughputValueChange(newInput)}
|
||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||
min={AutoPilotUtils.autoPilotThroughput1K}
|
||||
max={isSharded ? Number.MAX_SAFE_INTEGER.toString() : "10000"}
|
||||
@@ -268,16 +299,26 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
required={true}
|
||||
errorMessage={throughputError}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Text variant="small">
|
||||
Your {isDatabase ? "database" : getCollectionName().toLocaleLowerCase()} throughput will automatically scale
|
||||
from{" "}
|
||||
<b>
|
||||
{AutoPilotUtils.getMinRUsBasedOnUserInput(throughput)} RU/s (10% of max RU/s) - {throughput} RU/s
|
||||
</b>{" "}
|
||||
based on usage.
|
||||
<CostEstimateText requestUnits={throughput} isAutoscale={isAutoscaleSelected} />
|
||||
<Stack className="throughputInputSpacing">
|
||||
<Text variant="small" aria-label="ruDescription">
|
||||
Estimate your required RU/s with
|
||||
<Link
|
||||
className="underlinedLink"
|
||||
target="_blank"
|
||||
href="https://cosmos.azure.com/capacitycalculator/"
|
||||
aria-label="Capacity calculator"
|
||||
>
|
||||
capacity calculator
|
||||
</Link>
|
||||
.
|
||||
</Text>
|
||||
</Stack>
|
||||
<Separator className="panelSeparator" style={{ paddingTop: -8, paddingBottom: -8 }} />
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{!isAutoscaleSelected && (
|
||||
@@ -300,7 +341,6 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
</Text>
|
||||
<InfoTooltip>{getAutoScaleTooltip()}</InfoTooltip>
|
||||
</Stack>
|
||||
|
||||
<TooltipHost
|
||||
directionalHint={DirectionalHint.topLeftEdge}
|
||||
content={
|
||||
@@ -325,11 +365,10 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
errorMessage={throughputError}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<CostEstimateText requestUnits={throughput} isAutoscale={isAutoscaleSelected} />
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<CostEstimateText requestUnits={throughput} isAutoscale={isAutoscaleSelected} />
|
||||
|
||||
{throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && (
|
||||
<Stack horizontal verticalAlign="start">
|
||||
<Checkbox
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@ import { readDatabases } from "../Common/dataAccess/readDatabases";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import { ContainerConnectionInfo, IPhoenixServiceInfo, IProvisionData, IResponse } from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { UploadDetailsRecord } from "../Contracts/ViewModels";
|
||||
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
||||
import { PhoenixClient } from "../Phoenix/PhoenixClient";
|
||||
import * as ExplorerSettings from "../Shared/ExplorerSettings";
|
||||
@@ -71,7 +72,6 @@ import { ResourceTreeAdapter } from "./Tree/ResourceTreeAdapter";
|
||||
import StoredProcedure from "./Tree/StoredProcedure";
|
||||
import { useDatabases } from "./useDatabases";
|
||||
import { useSelectedNode } from "./useSelectedNode";
|
||||
import { UploadDetailsRecord } from "../Contracts/ViewModels";
|
||||
|
||||
BindingHandlersRegisterer.registerBindingHandlers();
|
||||
|
||||
|
||||
@@ -16,7 +16,12 @@ import * as StorageUtility from "../../../Shared/StorageUtility";
|
||||
import { LocalStorageUtility, StorageKey } from "../../../Shared/StorageUtility";
|
||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
||||
import {
|
||||
logConsoleError,
|
||||
logConsoleInfo,
|
||||
logConsoleProgress,
|
||||
logConsoleWarning,
|
||||
} from "../../../Utils/NotificationConsoleUtils";
|
||||
import { EditorReact } from "../../Controls/Editor/EditorReact";
|
||||
import * as InputTypeaheadComponent from "../../Controls/InputTypeahead/InputTypeaheadComponent";
|
||||
import * as TabComponent from "../../Controls/Tabs/TabComponent";
|
||||
@@ -1083,6 +1088,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||
public static reportToConsole(type: ConsoleDataType.InProgress, msg: string, ...errorData: any[]): () => void;
|
||||
public static reportToConsole(type: ConsoleDataType.Info, msg: string, ...errorData: any[]): void;
|
||||
public static reportToConsole(type: ConsoleDataType.Error, msg: string, ...errorData: any[]): void;
|
||||
public static reportToConsole(type: ConsoleDataType.Warning, msg: string, ...errorData: any[]): void;
|
||||
public static reportToConsole(type: ConsoleDataType, msg: string, ...errorData: any[]): void | (() => void) {
|
||||
let errorDataStr = "";
|
||||
if (errorData && errorData.length > 0) {
|
||||
@@ -1099,6 +1105,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
||||
return logConsoleInfo(consoleMessage);
|
||||
case ConsoleDataType.InProgress:
|
||||
return logConsoleProgress(consoleMessage);
|
||||
case ConsoleDataType.Warning:
|
||||
return logConsoleWarning(consoleMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,3 +95,10 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.newVertexComponent {
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,5 @@ export enum ConsoleDataType {
|
||||
Info = 0,
|
||||
Error = 1,
|
||||
InProgress = 2,
|
||||
Warning = 3,
|
||||
}
|
||||
|
||||
@@ -173,8 +173,20 @@
|
||||
.message {
|
||||
flex-grow: 1;
|
||||
white-space:pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.notificationConsoleContents {
|
||||
overflow-y: auto;
|
||||
|
||||
.notificationConsoleData {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import ErrorRedIcon from "../../../../images/error_red.svg";
|
||||
import infoBubbleIcon from "../../../../images/info-bubble-9x9.svg";
|
||||
import InfoIcon from "../../../../images/info_color.svg";
|
||||
import LoadingIcon from "../../../../images/loading.svg";
|
||||
import WarningIcon from "../../../../images/warning.svg";
|
||||
import { ClientDefaults, KeyCodes } from "../../../Common/Constants";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import { useNotificationConsole } from "../../../hooks/useNotificationConsole";
|
||||
@@ -91,6 +92,9 @@ export class NotificationConsoleComponent extends React.Component<
|
||||
const numInfoItems = this.state.allConsoleData.filter(
|
||||
(data: ConsoleData) => data.type === ConsoleDataType.Info,
|
||||
).length;
|
||||
const numWarningItems = this.state.allConsoleData.filter(
|
||||
(data: ConsoleData) => data.type === ConsoleDataType.Warning,
|
||||
).length;
|
||||
|
||||
return (
|
||||
<div className="notificationConsoleContainer">
|
||||
@@ -118,6 +122,10 @@ export class NotificationConsoleComponent extends React.Component<
|
||||
<img src={infoBubbleIcon} alt="Info items" />
|
||||
<span className="numInfoItems">{numInfoItems}</span>
|
||||
</span>
|
||||
<span className="notificationConsoleHeaderIconWithData">
|
||||
<img src={WarningIcon} alt="Warning items" />
|
||||
<span className="numWarningItems">{numWarningItems}</span>
|
||||
</span>
|
||||
</span>
|
||||
{userContext.features.pr && <PrPreview pr={userContext.features.pr} />}
|
||||
<span className="consoleSplitter" />
|
||||
@@ -198,6 +206,7 @@ export class NotificationConsoleComponent extends React.Component<
|
||||
{item.type === ConsoleDataType.Info && <img className="infoIcon" src={InfoIcon} alt="info" />}
|
||||
{item.type === ConsoleDataType.Error && <img className="errorIcon" src={ErrorRedIcon} alt="error" />}
|
||||
{item.type === ConsoleDataType.InProgress && <img className="loaderIcon" src={LoaderIcon} alt="in progress" />}
|
||||
{item.type === ConsoleDataType.Warning && <img className="warningIcon" src={WarningIcon} alt="warning" />}
|
||||
<span className="date">{item.date}</span>
|
||||
<span className="message" role="alert" aria-live="assertive">
|
||||
{item.message}
|
||||
|
||||
@@ -59,6 +59,19 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
|
||||
0
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="notificationConsoleHeaderIconWithData"
|
||||
>
|
||||
<img
|
||||
alt="Warning items"
|
||||
src={{}}
|
||||
/>
|
||||
<span
|
||||
className="numWarningItems"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="consoleSplitter"
|
||||
@@ -229,6 +242,19 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
||||
1
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="notificationConsoleHeaderIconWithData"
|
||||
>
|
||||
<img
|
||||
alt="Warning items"
|
||||
src={{}}
|
||||
/>
|
||||
<span
|
||||
className="numWarningItems"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="consoleSplitter"
|
||||
|
||||
@@ -188,6 +188,11 @@ function openPane(action: ActionContracts.OpenPane, explorer: Explorer) {
|
||||
action.paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.AddCollection]
|
||||
) {
|
||||
explorer.onNewCollectionClicked();
|
||||
} else if (
|
||||
action.paneKind === ActionContracts.PaneKind.QuickStart ||
|
||||
action.paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.QuickStart]
|
||||
) {
|
||||
explorer.onNewCollectionClicked({ isQuickstart: true });
|
||||
} else if (
|
||||
action.paneKind === ActionContracts.PaneKind.CassandraAddCollection ||
|
||||
action.paneKind === ActionContracts.PaneKind[ActionContracts.PaneKind.CassandraAddCollection]
|
||||
|
||||
@@ -25,7 +25,7 @@ import { FullTextPoliciesComponent } from "Explorer/Controls/FullTextSeach/FullT
|
||||
import { VectorEmbeddingPoliciesComponent } from "Explorer/Controls/VectorSearch/VectorEmbeddingPoliciesComponent";
|
||||
import {
|
||||
AllPropertiesIndexed,
|
||||
AnalyticalStorageContent,
|
||||
AnalyticalStoreHeader,
|
||||
ContainerVectorPolicyTooltipContent,
|
||||
FullTextPolicyDefault,
|
||||
getPartitionKey,
|
||||
@@ -49,12 +49,7 @@ import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "UserContext";
|
||||
import { getCollectionName } from "Utils/APITypeUtils";
|
||||
import {
|
||||
isCapabilityEnabled,
|
||||
isFullTextSearchEnabled,
|
||||
isServerlessAccount,
|
||||
isVectorSearchEnabled,
|
||||
} from "Utils/CapabilityUtils";
|
||||
import { isCapabilityEnabled, isServerlessAccount, isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
||||
import { getUpsellMessage } from "Utils/PricingUtils";
|
||||
import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils";
|
||||
import { CollapsibleSectionComponent } from "../../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
||||
@@ -65,6 +60,7 @@ import { useDatabases } from "../../useDatabases";
|
||||
import { PanelFooterComponent } from "../PanelFooterComponent";
|
||||
import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent";
|
||||
import { PanelLoadingScreen } from "../PanelLoadingScreen";
|
||||
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
||||
|
||||
export interface AddCollectionPanelProps {
|
||||
explorer: Explorer;
|
||||
@@ -110,6 +106,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
private collectionThroughput: number;
|
||||
private isCollectionAutoscale: boolean;
|
||||
private isCostAcknowledged: boolean;
|
||||
private showFullTextSearch: boolean;
|
||||
|
||||
constructor(props: AddCollectionPanelProps) {
|
||||
super(props);
|
||||
@@ -144,6 +141,8 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
fullTextIndexes: [],
|
||||
fullTextPolicyValidated: true,
|
||||
};
|
||||
|
||||
this.showFullTextSearch = userContext.apiType === "SQL";
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
@@ -266,7 +265,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
|
||||
<div className="panelMainContent">
|
||||
{!(isFabricNative() && this.props.databaseId !== undefined) && (
|
||||
<Stack hidden={userContext.apiType === "Tables"}>
|
||||
<Stack hidden={userContext.apiType === "Tables"} style={{ marginBottom: -2 }}>
|
||||
<Stack horizontal>
|
||||
<span className="mandatoryStar">* </span>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
@@ -337,7 +336,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
size={40}
|
||||
className="panelTextField"
|
||||
aria-label="New database id, Type a new database id"
|
||||
autoFocus
|
||||
tabIndex={0}
|
||||
value={this.state.newDatabaseId}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
@@ -408,12 +406,12 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
responsiveMode={999}
|
||||
/>
|
||||
)}
|
||||
<Separator className="panelSeparator" />
|
||||
</Stack>
|
||||
)}
|
||||
<Separator className="panelSeparator" style={{ marginTop: -4, marginBottom: -4 }} />
|
||||
|
||||
<Stack>
|
||||
<Stack horizontal>
|
||||
<Stack horizontal style={{ marginTop: -5, marginBottom: 1 }}>
|
||||
<span className="mandatoryStar">* </span>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
{`${getCollectionName()} id`}
|
||||
@@ -451,10 +449,10 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Separator className="panelSeparator" style={{ marginTop: -5, marginBottom: -5 }} />
|
||||
{this.shouldShowIndexingOptionsForFreeTierAccount() && (
|
||||
<Stack>
|
||||
<Stack horizontal>
|
||||
<Stack horizontal style={{ marginTop: -4, marginBottom: -5 }}>
|
||||
<span className="mandatoryStar">* </span>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
Indexing
|
||||
@@ -500,7 +498,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
(!this.state.isSharedThroughputChecked ||
|
||||
this.props.explorer.isFixedCollectionWithSharedThroughputSupported()) && (
|
||||
<Stack>
|
||||
<Stack horizontal>
|
||||
<Stack horizontal style={{ marginTop: -5, marginBottom: -4 }}>
|
||||
<span className="mandatoryStar">* </span>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
Sharding
|
||||
@@ -556,7 +554,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
|
||||
{this.state.isSharded && (
|
||||
<Stack>
|
||||
<Stack horizontal>
|
||||
<Stack horizontal style={{ marginTop: -5, marginBottom: -4 }}>
|
||||
<span className="mandatoryStar">* </span>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
{getPartitionKeyName()}
|
||||
@@ -600,7 +598,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
{userContext.apiType === "SQL" &&
|
||||
this.state.subPartitionKeys.map((subPartitionKey: string, index: number) => {
|
||||
return (
|
||||
<Stack style={{ marginBottom: 8 }} key={`uniqueKey${index}`} horizontal>
|
||||
<Stack style={{ marginBottom: 2, marginTop: -5 }} key={`uniqueKey${index}`} horizontal>
|
||||
<div
|
||||
style={{
|
||||
width: "20px",
|
||||
@@ -668,6 +666,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
<Separator className="panelSeparator" style={{ marginTop: 2, marginBottom: -4 }} />
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
@@ -728,7 +727,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
)}
|
||||
|
||||
{!isFabricNative() && userContext.apiType === "SQL" && (
|
||||
<Stack>
|
||||
<Stack style={{ marginTop: -2, marginBottom: -4 }}>
|
||||
{UniqueKeysHeader()}
|
||||
{this.state.uniqueKeys.map((uniqueKey: string, i: number): JSX.Element => {
|
||||
return (
|
||||
@@ -742,7 +741,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
: "Comma separated paths e.g. /firstName,/address/zipCode"
|
||||
}
|
||||
className="panelTextField"
|
||||
autoFocus
|
||||
value={uniqueKey}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => {
|
||||
@@ -777,10 +775,12 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<Separator className="panelSeparator" style={{ marginTop: -15, marginBottom: -4 }} />
|
||||
|
||||
{shouldShowAnalyticalStoreOptions() && (
|
||||
<Stack className="panelGroupSpacing">
|
||||
<Stack className="panelGroupSpacing" style={{ marginTop: -4 }}>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
{AnalyticalStorageContent()}
|
||||
{AnalyticalStoreHeader()}
|
||||
</Text>
|
||||
|
||||
<Stack horizontal verticalAlign="center">
|
||||
@@ -821,7 +821,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
<Stack className="panelGroupSpacing">
|
||||
<Text variant="small">
|
||||
Azure Synapse Link is required for creating an analytical store{" "}
|
||||
{getCollectionName().toLocaleLowerCase()}. Enable Synapse Link for this Cosmos DB account.{" "}
|
||||
{getCollectionName().toLocaleLowerCase()}. Enable Synapse Link for this Cosmos DB account. <br />
|
||||
<Link
|
||||
href="https://aka.ms/cosmosdb-synapselink"
|
||||
target="_blank"
|
||||
@@ -1161,7 +1161,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
}
|
||||
|
||||
private shouldShowFullTextSearchParameters() {
|
||||
return isFullTextSearchEnabled() && (isServerlessAccount() || this.shouldShowCollectionThroughputInput());
|
||||
return !isFabricNative() && this.showFullTextSearch;
|
||||
}
|
||||
|
||||
private parseUniqueKeys(): DataModels.UniqueKeyPolicy {
|
||||
@@ -1316,7 +1316,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.shouldShowFullTextSearchParameters()) {
|
||||
if (this.showFullTextSearch) {
|
||||
indexingPolicy.fullTextIndexes = this.state.fullTextIndexes;
|
||||
}
|
||||
|
||||
@@ -1350,7 +1350,12 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
let offerThroughput: number;
|
||||
let autoPilotMaxThroughput: number;
|
||||
|
||||
if (databaseLevelThroughput) {
|
||||
// Throughput
|
||||
if (isFabricNative()) {
|
||||
// Fabric Native accounts are always autoscale and have a fixed throughput of 1K
|
||||
autoPilotMaxThroughput = AutoPilotUtils.autoPilotThroughput1K;
|
||||
offerThroughput = undefined;
|
||||
} else if (databaseLevelThroughput) {
|
||||
if (this.state.createNewDatabase) {
|
||||
if (this.isNewDatabaseAutoscale) {
|
||||
autoPilotMaxThroughput = this.newDatabaseThroughput;
|
||||
|
||||
@@ -73,7 +73,7 @@ export function UniqueKeysHeader(): JSX.Element {
|
||||
"Unique keys provide developers with the ability to add a layer of data integrity to their database. By creating a unique key policy when a container is created, you ensure the uniqueness of one or more values per partition key.";
|
||||
|
||||
return (
|
||||
<Stack horizontal>
|
||||
<Stack horizontal style={{ marginBottom: -2 }}>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
Unique keys
|
||||
</Text>
|
||||
@@ -98,6 +98,21 @@ export function shouldShowAnalyticalStoreOptions(): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
export function AnalyticalStoreHeader(): JSX.Element {
|
||||
const tooltipContent =
|
||||
"Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads.";
|
||||
return (
|
||||
<Stack horizontal style={{ marginBottom: -2 }}>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
Analytical Store
|
||||
</Text>
|
||||
<TooltipHost directionalHint={DirectionalHint.bottomLeftEdge} content={tooltipContent}>
|
||||
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} ariaLabel={tooltipContent} />
|
||||
</TooltipHost>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export function AnalyticalStorageContent(): JSX.Element {
|
||||
return (
|
||||
<Text variant="small">
|
||||
|
||||
@@ -11,6 +11,11 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
>
|
||||
<Stack
|
||||
hidden={false}
|
||||
style={
|
||||
{
|
||||
"marginBottom": -2,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
@@ -88,7 +93,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
aria-label="New database id, Type a new database id"
|
||||
aria-required={true}
|
||||
autoComplete="off"
|
||||
autoFocus={true}
|
||||
className="panelTextField"
|
||||
id="newDatabaseId"
|
||||
name="newDatabaseId"
|
||||
@@ -138,13 +142,25 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
</StyledTooltipHostBase>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Separator
|
||||
className="panelSeparator"
|
||||
style={
|
||||
{
|
||||
"marginBottom": -4,
|
||||
"marginTop": -4,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
style={
|
||||
{
|
||||
"marginBottom": 1,
|
||||
"marginTop": -5,
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="mandatoryStar"
|
||||
@@ -187,9 +203,24 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
value=""
|
||||
/>
|
||||
</Stack>
|
||||
<Separator
|
||||
className="panelSeparator"
|
||||
style={
|
||||
{
|
||||
"marginBottom": -5,
|
||||
"marginTop": -5,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Stack>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
style={
|
||||
{
|
||||
"marginBottom": -4,
|
||||
"marginTop": -5,
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="mandatoryStar"
|
||||
@@ -254,6 +285,15 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
Add hierarchical partition key
|
||||
</CustomizedDefaultButton>
|
||||
</Stack>
|
||||
<Separator
|
||||
className="panelSeparator"
|
||||
style={
|
||||
{
|
||||
"marginBottom": -4,
|
||||
"marginTop": 2,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
<ThroughputInput
|
||||
isDatabase={false}
|
||||
@@ -263,9 +303,21 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
setIsThroughputCapExceeded={[Function]}
|
||||
setThroughputValue={[Function]}
|
||||
/>
|
||||
<Stack>
|
||||
<Stack
|
||||
style={
|
||||
{
|
||||
"marginBottom": -4,
|
||||
"marginTop": -2,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
style={
|
||||
{
|
||||
"marginBottom": -2,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
className="panelTextBold"
|
||||
@@ -306,26 +358,53 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
Add unique key
|
||||
</CustomizedActionButton>
|
||||
</Stack>
|
||||
<Separator
|
||||
className="panelSeparator"
|
||||
style={
|
||||
{
|
||||
"marginBottom": -4,
|
||||
"marginTop": -15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Stack
|
||||
className="panelGroupSpacing"
|
||||
style={
|
||||
{
|
||||
"marginTop": -4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
className="panelTextBold"
|
||||
variant="small"
|
||||
>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
style={
|
||||
{
|
||||
"marginBottom": -2,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
className="panelTextBold"
|
||||
variant="small"
|
||||
>
|
||||
Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads.
|
||||
|
||||
<StyledLinkBase
|
||||
aria-label="Learn more about analytical store."
|
||||
href="https://aka.ms/analytical-store-overview"
|
||||
target="_blank"
|
||||
>
|
||||
Learn more
|
||||
</StyledLinkBase>
|
||||
Analytical Store
|
||||
</Text>
|
||||
<StyledTooltipHostBase
|
||||
content="Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads."
|
||||
directionalHint={4}
|
||||
>
|
||||
<Icon
|
||||
ariaLabel="Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads."
|
||||
className="panelInfoIcon"
|
||||
iconName="Info"
|
||||
tabIndex={0}
|
||||
/>
|
||||
</StyledTooltipHostBase>
|
||||
</Stack>
|
||||
</Text>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
@@ -382,7 +461,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
|
||||
container
|
||||
. Enable Synapse Link for this Cosmos DB account.
|
||||
|
||||
<br />
|
||||
<StyledLinkBase
|
||||
aria-label="Learn more about Azure Synapse Link."
|
||||
className="capacitycalculator-link"
|
||||
@@ -411,6 +490,44 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<CollapsibleSectionComponent
|
||||
isExpandedByDefault={false}
|
||||
onExpand={[Function]}
|
||||
title="Container Full Text Search Policy"
|
||||
>
|
||||
<Stack
|
||||
id="collapsibleFullTextPolicySectionContent"
|
||||
styles={
|
||||
{
|
||||
"root": {
|
||||
"position": "relative",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<Stack
|
||||
styles={
|
||||
{
|
||||
"root": {
|
||||
"paddingLeft": 40,
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<FullTextPoliciesComponent
|
||||
fullTextPolicy={
|
||||
{
|
||||
"defaultLanguage": "en-US",
|
||||
"fullTextPaths": [],
|
||||
}
|
||||
}
|
||||
onFullTextPathChange={[Function]}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</CollapsibleSectionComponent>
|
||||
</Stack>
|
||||
<CollapsibleSectionComponent
|
||||
isExpandedByDefault={false}
|
||||
onExpand={[Function]}
|
||||
|
||||
@@ -40,12 +40,12 @@ import { PanelInfoErrorComponent } from "Explorer/Panes/PanelInfoErrorComponent"
|
||||
import { PanelLoadingScreen } from "Explorer/Panes/PanelLoadingScreen";
|
||||
import { useDatabases } from "Explorer/useDatabases";
|
||||
import { useSidePanel } from "hooks/useSidePanel";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import { CollectionCreation } from "Shared/Constants";
|
||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "UserContext";
|
||||
import { isFullTextSearchEnabled, isServerlessAccount, isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
||||
import { isServerlessAccount, isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
||||
import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils";
|
||||
|
||||
export interface AddGlobalSecondaryIndexPanelProps {
|
||||
@@ -75,6 +75,8 @@ export const AddGlobalSecondaryIndexPanel = (props: AddGlobalSecondaryIndexPanel
|
||||
const [showErrorDetails, setShowErrorDetails] = useState<boolean>();
|
||||
const [isExecuting, setIsExecuting] = useState<boolean>();
|
||||
|
||||
const showFullTextSearch: MutableRefObject<boolean> = useRef<boolean>(userContext.apiType === "SQL");
|
||||
|
||||
useEffect(() => {
|
||||
const sourceContainerOptions: IDropdownOption[] = [];
|
||||
useDatabases.getState().databases.forEach((database: Database) => {
|
||||
@@ -140,10 +142,6 @@ export const AddGlobalSecondaryIndexPanel = (props: AddGlobalSecondaryIndexPanel
|
||||
return isVectorSearchEnabled() && (isServerlessAccount() || showCollectionThroughputInput());
|
||||
};
|
||||
|
||||
const showFullTextSearchParameters = (): boolean => {
|
||||
return isFullTextSearchEnabled() && (isServerlessAccount() || showCollectionThroughputInput());
|
||||
};
|
||||
|
||||
const getAnalyticalStorageTtl = (): number => {
|
||||
if (!isSynapseLinkEnabled()) {
|
||||
return undefined;
|
||||
@@ -228,7 +226,7 @@ export const AddGlobalSecondaryIndexPanel = (props: AddGlobalSecondaryIndexPanel
|
||||
};
|
||||
}
|
||||
|
||||
if (showFullTextSearchParameters()) {
|
||||
if (showFullTextSearch) {
|
||||
indexingPolicy.fullTextIndexes = fullTextIndexes;
|
||||
}
|
||||
|
||||
@@ -387,7 +385,7 @@ export const AddGlobalSecondaryIndexPanel = (props: AddGlobalSecondaryIndexPanel
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{showFullTextSearchParameters() && (
|
||||
{showFullTextSearch && (
|
||||
<FullTextSearchComponent
|
||||
{...{ fullTextPolicy, setFullTextPolicy, setFullTextIndexes, setFullTextPolicyValidated }}
|
||||
/>
|
||||
|
||||
@@ -172,6 +172,17 @@ exports[`AddGlobalSecondaryIndexPanel render default panel 1`] = `
|
||||
}
|
||||
setEnableAnalyticalStore={[Function]}
|
||||
/>
|
||||
<FullTextSearchComponent
|
||||
fullTextPolicy={
|
||||
{
|
||||
"defaultLanguage": "en-US",
|
||||
"fullTextPaths": [],
|
||||
}
|
||||
}
|
||||
setFullTextIndexes={[Function]}
|
||||
setFullTextPolicy={[Function]}
|
||||
setFullTextPolicyValidated={[Function]}
|
||||
/>
|
||||
<AdvancedComponent
|
||||
setSubPartitionKeys={[Function]}
|
||||
setUseHashV1={[Function]}
|
||||
|
||||
@@ -56,6 +56,14 @@
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.panelMainContent {
|
||||
padding: 0 24px;
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panelHeader {
|
||||
@@ -113,17 +121,21 @@
|
||||
.deleteCollectionFeedback {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.addRemoveIcon {
|
||||
margin-left: 4px !important;
|
||||
}
|
||||
|
||||
.addRemoveIconLabel {
|
||||
margin-top: 28px;
|
||||
margin-left: 4px !important;
|
||||
}
|
||||
|
||||
.addRemoveIcon [alt="editEntity"]:focus,
|
||||
.addRemoveIconLabel [alt="editEntity"]:focus {
|
||||
border: 1px dashed #605e5c;
|
||||
}
|
||||
|
||||
.addNewParamStyle {
|
||||
margin-top: 5px;
|
||||
margin-left: 5px !important;
|
||||
@@ -133,50 +145,63 @@
|
||||
.panelGroupSpacing> :not(:last-child) {
|
||||
margin-bottom: @DefaultSpace;
|
||||
}
|
||||
|
||||
.fileUpload {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.customFileUpload {
|
||||
padding: 25px 0px 0px 10px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.fileIcon {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.panelAddIconLabel {
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
margin: 30px 0 0 10px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.panelAddIcon {
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
margin: 30px 0 0 10px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.removeIcon {
|
||||
color: @InfoIconColor;
|
||||
}
|
||||
|
||||
.backImageIcon {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
[alt="back"]:focus {
|
||||
border: 1px solid #605e5c;
|
||||
}
|
||||
|
||||
.addEntityDatePicker {
|
||||
max-width: 145px;
|
||||
}
|
||||
|
||||
.addEntityTextField {
|
||||
width: 237px;
|
||||
}
|
||||
|
||||
.addButtonEntiy {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.column-select-view {
|
||||
margin: 20px 0px 0px 0px;
|
||||
}
|
||||
|
||||
.panelSeparator::before {
|
||||
background-color: #edebe9;
|
||||
}
|
||||
@@ -180,6 +180,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
? LocalStorageUtility.getEntryNumber(StorageKey.MaxWaitTimeInSeconds)
|
||||
: Constants.Queries.DefaultMaxWaitTimeInSeconds,
|
||||
);
|
||||
const [queryControlEnabled, setQueryControlEnabled] = useState<boolean>(
|
||||
LocalStorageUtility.hasItem(StorageKey.QueryControlEnabled)
|
||||
? LocalStorageUtility.getEntryString(StorageKey.QueryControlEnabled) === "true"
|
||||
: false,
|
||||
);
|
||||
const [maxDegreeOfParallelism, setMaxDegreeOfParallelism] = useState<number>(
|
||||
LocalStorageUtility.hasItem(StorageKey.MaxDegreeOfParellism)
|
||||
? LocalStorageUtility.getEntryNumber(StorageKey.MaxDegreeOfParellism)
|
||||
@@ -204,6 +209,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
!isEmulator;
|
||||
const shouldShowGraphAutoVizOption = userContext.apiType === "Gremlin" && !isEmulator;
|
||||
const shouldShowCrossPartitionOption = userContext.apiType !== "Gremlin" && !isEmulator;
|
||||
const shouldShowEnhancedQueryControl = userContext.apiType === "SQL";
|
||||
const shouldShowParallelismOption = userContext.apiType !== "Gremlin" && !isEmulator;
|
||||
const showEnableEntraIdRbac =
|
||||
isDataplaneRbacSupported(userContext.apiType) &&
|
||||
@@ -381,6 +387,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.MaxWaitTimeInSeconds, MaxWaitTimeInSeconds);
|
||||
LocalStorageUtility.setEntryString(StorageKey.ContainerPaginationEnabled, containerPaginationEnabled.toString());
|
||||
LocalStorageUtility.setEntryString(StorageKey.IsCrossPartitionQueryEnabled, crossPartitionQueryEnabled.toString());
|
||||
LocalStorageUtility.setEntryString(StorageKey.QueryControlEnabled, queryControlEnabled.toString());
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.MaxDegreeOfParellism, maxDegreeOfParallelism);
|
||||
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, priorityLevel.toString());
|
||||
LocalStorageUtility.setEntryString(StorageKey.CopilotSampleDBEnabled, copilotSampleDBEnabled.toString());
|
||||
@@ -410,6 +417,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
`Updated items per page setting to ${LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage)}`,
|
||||
);
|
||||
logConsoleInfo(`${crossPartitionQueryEnabled ? "Enabled" : "Disabled"} cross-partition query feed option`);
|
||||
logConsoleInfo(`${queryControlEnabled ? "Enabled" : "Disabled"} query control option`);
|
||||
logConsoleInfo(
|
||||
`Updated the max degree of parallelism query feed option to ${LocalStorageUtility.getEntryNumber(
|
||||
StorageKey.MaxDegreeOfParellism,
|
||||
@@ -760,7 +768,6 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
)}
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem value="5">
|
||||
<AccordionHeader>
|
||||
<div className={styles.header}>RU Limit</div>
|
||||
@@ -943,6 +950,38 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
)}
|
||||
{shouldShowEnhancedQueryControl && (
|
||||
<AccordionItem value="10">
|
||||
<AccordionHeader>
|
||||
<div className={styles.header}>Enhanced query control</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<div className={styles.settingsSectionContainer}>
|
||||
<div className={styles.settingsSectionDescription}>
|
||||
Query up to the max degree of parallelism.
|
||||
<a
|
||||
href="https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/performance-tips-query-sdk?tabs=v3&pivots=programming-language-nodejs#enhanced-query-control"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{" "}
|
||||
Learn more{" "}
|
||||
</a>
|
||||
</div>
|
||||
<Checkbox
|
||||
styles={{
|
||||
label: { padding: 0 },
|
||||
}}
|
||||
className="padding"
|
||||
ariaLabel="EnableQueryControl"
|
||||
checked={queryControlEnabled}
|
||||
onChange={() => setQueryControlEnabled(!queryControlEnabled)}
|
||||
label="Enable query control"
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
)}
|
||||
{shouldShowParallelismOption && (
|
||||
<AccordionItem value="10">
|
||||
<AccordionHeader>
|
||||
|
||||
@@ -495,6 +495,51 @@ exports[`Settings Pane should render Default properly 1`] = `
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
<AccordionItem
|
||||
value="10"
|
||||
>
|
||||
<AccordionHeader>
|
||||
<div
|
||||
className="___15c001r_0000000 fq02s40"
|
||||
>
|
||||
Enhanced query control
|
||||
</div>
|
||||
</AccordionHeader>
|
||||
<AccordionPanel>
|
||||
<div
|
||||
className="___1dfa554_0000000 fo7qwa0"
|
||||
>
|
||||
<div
|
||||
className="___10gar1i_0000000 f1fow5ox f1ugzwwg"
|
||||
>
|
||||
Query up to the max degree of parallelism.
|
||||
<a
|
||||
href="https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/performance-tips-query-sdk?tabs=v3&pivots=programming-language-nodejs#enhanced-query-control"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
|
||||
Learn more
|
||||
|
||||
</a>
|
||||
</div>
|
||||
<StyledCheckboxBase
|
||||
ariaLabel="EnableQueryControl"
|
||||
checked={false}
|
||||
className="padding"
|
||||
label="Enable query control"
|
||||
onChange={[Function]}
|
||||
styles={
|
||||
{
|
||||
"label": {
|
||||
"padding": 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
<AccordionItem
|
||||
value="10"
|
||||
>
|
||||
|
||||
@@ -30,6 +30,21 @@
|
||||
margin: 0px auto;
|
||||
text-align: center;
|
||||
}
|
||||
.splashStackContainer {
|
||||
.splashStackRow {
|
||||
display: flex;
|
||||
gap: 0 16px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
gap: 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 85% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.mainButtonsContainer {
|
||||
.flex-display();
|
||||
|
||||
@@ -126,8 +126,12 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
useDatabases.getState().sampleDataResourceTokenCollection
|
||||
) {
|
||||
return (
|
||||
<Stack style={{ width: "66%", cursor: "pointer", margin: "40px auto" }} tokens={{ childrenGap: 16 }}>
|
||||
<Stack horizontal tokens={{ childrenGap: 16 }}>
|
||||
<Stack
|
||||
className="splashStackContainer"
|
||||
style={{ width: "66%", cursor: "pointer", margin: "40px auto" }}
|
||||
tokens={{ childrenGap: 16 }}
|
||||
>
|
||||
<Stack className="splashStackRow" horizontal>
|
||||
<SplashScreenButton
|
||||
imgSrc={QuickStartIcon}
|
||||
title={"Launch quick start"}
|
||||
@@ -147,7 +151,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal tokens={{ childrenGap: 16 }}>
|
||||
<Stack className="splashStackRow" horizontal>
|
||||
{useQueryCopilot.getState().copilotEnabled && (
|
||||
<SplashScreenButton
|
||||
imgSrc={CopilotIcon}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-console */
|
||||
import { FeedOptions, QueryOperationOptions } from "@azure/cosmos";
|
||||
import { FeedOptions } from "@azure/cosmos";
|
||||
import { AuthType } from "AuthType";
|
||||
import QueryError, { createMonacoErrorLocationResolver, createMonacoMarkersForQueryErrors } from "Common/QueryError";
|
||||
import { SplitterDirection } from "Common/Splitter";
|
||||
@@ -19,7 +19,7 @@ import { CosmosFluentProvider } from "Explorer/Theme/ThemeUtil";
|
||||
import { useSelectedNode } from "Explorer/useSelectedNode";
|
||||
import { KeyboardAction } from "KeyboardShortcuts";
|
||||
import { QueryConstants } from "Shared/Constants";
|
||||
import { LocalStorageUtility, StorageKey, getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
import { Allotment } from "allotment";
|
||||
import { useClientWriteEnabled } from "hooks/useClientWriteEnabled";
|
||||
@@ -369,22 +369,9 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
|
||||
this.setState({
|
||||
isExecutionError: false,
|
||||
});
|
||||
|
||||
let queryOperationOptions: QueryOperationOptions;
|
||||
if (userContext.apiType === "SQL" && ruThresholdEnabled()) {
|
||||
const ruThreshold: number = getRUThreshold();
|
||||
queryOperationOptions = {
|
||||
ruCapPerOperation: ruThreshold,
|
||||
} as QueryOperationOptions;
|
||||
}
|
||||
|
||||
this.props.tabsBaseInstance.isExecutionWarning(false);
|
||||
const queryDocuments = async (firstItemIndex: number) =>
|
||||
await queryDocumentsPage(
|
||||
this.props.collection && this.props.collection.id(),
|
||||
this._iterator,
|
||||
firstItemIndex,
|
||||
queryOperationOptions,
|
||||
);
|
||||
await queryDocumentsPage(this.props.collection && this.props.collection.id(), this._iterator, firstItemIndex);
|
||||
this.props.tabsBaseInstance.isExecuting(true);
|
||||
this.setState({
|
||||
isExecuting: true,
|
||||
@@ -424,6 +411,9 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
|
||||
firstItemIndex,
|
||||
queryDocuments,
|
||||
);
|
||||
if (queryResults.ruThresholdExceeded) {
|
||||
this.props.tabsBaseInstance.isExecutionWarning(true);
|
||||
}
|
||||
this.setState({ queryResults, errors: [] });
|
||||
} catch (error) {
|
||||
this.props.tabsBaseInstance.isExecutionError(true);
|
||||
|
||||
@@ -32,6 +32,7 @@ enum ResultsTabs {
|
||||
|
||||
const ResultsTab: React.FC<ResultsViewProps> = ({ queryResults, isMongoDB, executeQueryDocumentsPage }) => {
|
||||
const styles = useQueryTabStyles();
|
||||
/* eslint-disable react/prop-types */
|
||||
const queryResultsString = queryResults
|
||||
? isMongoDB
|
||||
? MongoUtility.tojson(queryResults.documents, undefined, false)
|
||||
@@ -47,6 +48,172 @@ const ResultsTab: React.FC<ResultsViewProps> = ({ queryResults, isMongoDB, execu
|
||||
await executeQueryDocumentsPage(firstItemIndex + itemCount - 1);
|
||||
};
|
||||
|
||||
const ExportResults: React.FC = () => {
|
||||
const [showDropdown, setShowDropdown] = useState(false);
|
||||
const dropdownRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
||||
setShowDropdown(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (showDropdown) {
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
}
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, [showDropdown]);
|
||||
|
||||
const escapeCsvValue = (value: string): string => {
|
||||
return `"${value.replace(/"/g, '""')}"`;
|
||||
};
|
||||
|
||||
const formatValueForCsv = (value: string | object): string => {
|
||||
if (value === null || value === undefined) {
|
||||
return "";
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
return escapeCsvValue(JSON.stringify(value));
|
||||
}
|
||||
return escapeCsvValue(String(value));
|
||||
};
|
||||
|
||||
const exportToCsv = () => {
|
||||
try {
|
||||
const allHeadersSet = new Set<string>();
|
||||
queryResults.documents.forEach((doc) => {
|
||||
Object.keys(doc).forEach((key) => allHeadersSet.add(key));
|
||||
});
|
||||
|
||||
const allHeaders = Array.from(allHeadersSet);
|
||||
const csvHeader = allHeaders.map(escapeCsvValue).join(",");
|
||||
const csvData = queryResults.documents
|
||||
.map((doc) =>
|
||||
allHeaders.map((header) => (doc[header] !== undefined ? formatValueForCsv(doc[header]) : "")).join(","),
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
const csvContent = `sep=,\n${csvHeader}\n${csvData}`;
|
||||
downloadFile(csvContent, "query-results.csv", "text/csv");
|
||||
} catch (error) {
|
||||
console.error("Failed to export CSV:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const exportToJson = () => {
|
||||
try {
|
||||
downloadFile(queryResultsString, "query-results.json", "application/json");
|
||||
} catch (error) {
|
||||
console.error("Failed to export JSON:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const downloadFile = (content: string, fileName: string, contentType: string) => {
|
||||
const blob = new Blob([content], { type: contentType });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const downloadLink = document.createElement("a");
|
||||
downloadLink.href = url;
|
||||
downloadLink.download = fileName;
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
setTimeout(() => URL.revokeObjectURL(url), 100);
|
||||
};
|
||||
|
||||
const handleExport = (format: "CSV" | "JSON") => {
|
||||
setShowDropdown(false);
|
||||
if (format === "CSV") {
|
||||
exportToCsv();
|
||||
} else {
|
||||
exportToJson();
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent, format: "CSV" | "JSON") => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
handleExport(format);
|
||||
} else if (e.key === "Escape") {
|
||||
setShowDropdown(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative", display: "inline-block" }} ref={dropdownRef}>
|
||||
<Button
|
||||
onClick={() => setShowDropdown((v) => !v)}
|
||||
size="small"
|
||||
appearance="transparent"
|
||||
icon={<ArrowDownloadRegular />}
|
||||
title="Download Query Results"
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded={showDropdown}
|
||||
/>
|
||||
{showDropdown && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
zIndex: 10,
|
||||
background: "white",
|
||||
border: "1px solid #ccc",
|
||||
borderRadius: 2,
|
||||
minWidth: 60,
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
|
||||
marginTop: 4,
|
||||
}}
|
||||
role="listbox"
|
||||
tabIndex={-1}
|
||||
>
|
||||
<button
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
padding: "8px 16px",
|
||||
background: "none",
|
||||
border: "none",
|
||||
textAlign: "left",
|
||||
cursor: "pointer",
|
||||
transition: "background 0.2s",
|
||||
}}
|
||||
onMouseOver={(e) => (e.currentTarget.style.background = "#f3f3f3")}
|
||||
onMouseOut={(e) => (e.currentTarget.style.background = "none")}
|
||||
onClick={() => handleExport("JSON")}
|
||||
onKeyDown={(e) => handleKeyDown(e, "JSON")}
|
||||
role="option"
|
||||
tabIndex={0}
|
||||
>
|
||||
JSON
|
||||
</button>
|
||||
<button
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
padding: "8px 16px",
|
||||
background: "none",
|
||||
border: "none",
|
||||
textAlign: "left",
|
||||
cursor: "pointer",
|
||||
transition: "background 0.2s",
|
||||
}}
|
||||
onMouseOver={(e) => (e.currentTarget.style.background = "#f3f3f3")}
|
||||
onMouseOut={(e) => (e.currentTarget.style.background = "none")}
|
||||
onClick={() => handleExport("CSV")}
|
||||
onKeyDown={(e) => handleKeyDown(e, "CSV")}
|
||||
role="option"
|
||||
tabIndex={0}
|
||||
>
|
||||
CSV
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.queryResultsBar}>
|
||||
@@ -67,6 +234,7 @@ const ResultsTab: React.FC<ResultsViewProps> = ({ queryResults, isMongoDB, execu
|
||||
aria-label="Copy"
|
||||
onClick={onClickCopyResults}
|
||||
/>
|
||||
<ExportResults />
|
||||
</div>
|
||||
<div className={styles.queryResultsViewer}>
|
||||
<EditorReact language={"json"} content={queryResultsString} isReadOnly={true} ariaLabel={"Query results"} />
|
||||
|
||||
@@ -18,6 +18,7 @@ import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
|
||||
import errorIcon from "../../../images/close-black.svg";
|
||||
import errorQuery from "../../../images/error_no_outline.svg";
|
||||
import warningIconSvg from "../../../images/warning.svg";
|
||||
import { useObservable } from "../../hooks/useObservable";
|
||||
import { ReactTabKind, useTabs } from "../../hooks/useTabs";
|
||||
import TabsBase from "./TabsBase";
|
||||
@@ -117,6 +118,9 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
|
||||
>
|
||||
<span className="statusIconContainer" style={{ width: tabKind === ReactTabKind.Home ? 0 : 18 }}>
|
||||
{useObservable(tab?.isExecutionError || ko.observable(false)) && <ErrorIcon tab={tab} active={active} />}
|
||||
{useObservable(tab?.isExecutionWarning || ko.observable(false)) && (
|
||||
<WarningIcon tab={tab} active={active} />
|
||||
)}
|
||||
{isTabExecuting(tab, tabKind) && (
|
||||
<img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" />
|
||||
)}
|
||||
@@ -194,6 +198,20 @@ const ErrorIcon = ({ tab, active }: { tab: Tab; active: boolean }) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
const WarningIcon = ({ tab, active }: { tab: Tab; active: boolean }) => (
|
||||
<div
|
||||
id="warningStatusIcon"
|
||||
role="button"
|
||||
title="Click to view more details"
|
||||
tabIndex={active ? 0 : undefined}
|
||||
className={active ? "actionsEnabled warningIconContainer" : "warningIconContainer"}
|
||||
onClick={({ nativeEvent: e }) => tab.onErrorDetailsClick(undefined, e)}
|
||||
onKeyPress={({ nativeEvent: e }) => tab.onErrorDetailsKeyPress(undefined, e)}
|
||||
>
|
||||
<img src={warningIconSvg} alt="Warning Icon" style={{ height: 15, marginBottom: 5 }} />
|
||||
</div>
|
||||
);
|
||||
|
||||
function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
const attrs = {
|
||||
|
||||
@@ -27,6 +27,7 @@ export default class TabsBase extends WaitsForTemplateViewModel {
|
||||
public tabTitle: ko.Observable<string>;
|
||||
public tabPath: ko.Observable<string>;
|
||||
public isExecutionError = ko.observable(false);
|
||||
public isExecutionWarning = ko.observable(false);
|
||||
public isExecuting = ko.observable(false);
|
||||
protected _theme: string;
|
||||
public onLoadStartKey: number;
|
||||
|
||||
@@ -21,6 +21,7 @@ export enum StorageKey {
|
||||
DatabaseAccountId,
|
||||
EncryptedKeyToken,
|
||||
IsCrossPartitionQueryEnabled,
|
||||
QueryControlEnabled,
|
||||
MaxDegreeOfParellism,
|
||||
IsGraphAutoVizDisabled,
|
||||
TenantId,
|
||||
|
||||
@@ -20,7 +20,3 @@ export const isServerlessAccount = (): boolean => {
|
||||
export const isVectorSearchEnabled = (): boolean => {
|
||||
return userContext.apiType === "SQL" && isCapabilityEnabled(Constants.CapabilityNames.EnableNoSQLVectorSearch);
|
||||
};
|
||||
|
||||
export const isFullTextSearchEnabled = (): boolean => {
|
||||
return userContext.apiType === "SQL" && isCapabilityEnabled(Constants.CapabilityNames.EnableNoSQLFullTextSearch);
|
||||
};
|
||||
|
||||
@@ -23,3 +23,7 @@ export const logConsoleError = (msg: string): void => {
|
||||
export const logConsoleInfo = (msg: string): void => {
|
||||
log(ConsoleDataType.Info, msg);
|
||||
};
|
||||
|
||||
export const logConsoleWarning = (msg: string): void => {
|
||||
log(ConsoleDataType.Warning, msg);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { PartitionKey, PartitionKeyDefinition } from "@azure/cosmos";
|
||||
import { getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility";
|
||||
import { userContext } from "UserContext";
|
||||
import { logConsoleWarning } from "Utils/NotificationConsoleUtils";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
|
||||
@@ -86,6 +89,18 @@ export const queryPagesUntilContentPresent = async (
|
||||
results.roundTrips = roundTrips;
|
||||
results.requestCharge = Number(results.requestCharge) + netRequestCharge;
|
||||
netRequestCharge = Number(results.requestCharge);
|
||||
|
||||
if (results.hasMoreResults && userContext.apiType === "SQL" && ruThresholdEnabled()) {
|
||||
const ruThreshold: number = getRUThreshold();
|
||||
if (netRequestCharge > ruThreshold) {
|
||||
logConsoleWarning(
|
||||
`Warning: Query has exceeded the Request Unit threshold of ${ruThreshold} RUs. Query results show only those documents returned before the threshold was exceeded`,
|
||||
);
|
||||
results.ruThresholdExceeded = true;
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
const resultsMetadata = {
|
||||
hasMoreResults: results.hasMoreResults,
|
||||
itemCount: results.itemCount,
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Lists the Cassandra keyspaces under an existing Azure Cosmos DB database account. */
|
||||
export async function listCassandraKeyspaces(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account and collection. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given collection, split by partition. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given collection and region, split by partition. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account, collection and region. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account and database. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account and region. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the properties of an existing Azure Cosmos DB database account. */
|
||||
export async function get(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Lists the graphs under an existing Azure Cosmos DB database account. */
|
||||
export async function listGraphs(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Lists the Gremlin databases under an existing Azure Cosmos DB database account. */
|
||||
export async function listGremlinDatabases(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* List Cosmos DB locations and their properties */
|
||||
export async function list(subscriptionId: string): Promise<Types.LocationListResult | Types.CloudError> {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Lists the MongoDB databases under an existing Azure Cosmos DB database account. */
|
||||
export async function listMongoDBDatabases(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Lists all of the available Cosmos DB Resource Provider operations. */
|
||||
export async function list(): Promise<Types.OperationListResult> {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given partition key range id. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given partition key range id and region. */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given database account. This url is only for PBS and Replication Latency data */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given account, source and target region. This url is only for PBS and Replication Latency data */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Retrieves the metrics determined by the given filter for the given account target region. This url is only for PBS and Replication Latency data */
|
||||
export async function listMetrics(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Lists the SQL databases under an existing Azure Cosmos DB database account. */
|
||||
export async function listSqlDatabases(
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
import { armRequest } from "../../request";
|
||||
import * as Types from "./types";
|
||||
const apiVersion = "2024-12-01-preview";
|
||||
import { configContext } from "../../../../ConfigContext";
|
||||
const apiVersion = "2025-05-01-preview";
|
||||
|
||||
/* Lists the Tables under an existing Azure Cosmos DB database account. */
|
||||
export async function listTables(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Run "npm run generateARMClients" to regenerate
|
||||
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
|
||||
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2024-12-01-preview/cosmos-db.json
|
||||
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/preview/2025-05-01-preview/cosmos-db.json
|
||||
*/
|
||||
|
||||
/* The List operation response, that contains the client encryption keys and their properties. */
|
||||
@@ -580,6 +580,8 @@ export interface DatabaseAccountGetProperties {
|
||||
|
||||
/* Flag to indicate enabling/disabling of Per-Region Per-partition autoscale Preview feature on the account */
|
||||
enablePerRegionPerPartitionAutoscale?: boolean;
|
||||
/* Flag to indicate if All Versions and Deletes Change feed feature is enabled on the account */
|
||||
enableAllVersionsAndDeletesChangeFeed?: boolean;
|
||||
}
|
||||
|
||||
/* Properties to create and update Azure Cosmos DB database accounts. */
|
||||
@@ -682,6 +684,8 @@ export interface DatabaseAccountCreateUpdateProperties {
|
||||
|
||||
/* Flag to indicate enabling/disabling of Per-Region Per-partition autoscale Preview feature on the account */
|
||||
enablePerRegionPerPartitionAutoscale?: boolean;
|
||||
/* Flag to indicate if All Versions and Deletes Change feed feature is enabled on the account */
|
||||
enableAllVersionsAndDeletesChangeFeed?: boolean;
|
||||
}
|
||||
|
||||
/* Parameters to create and update Cosmos DB database accounts. */
|
||||
@@ -787,6 +791,8 @@ export interface DatabaseAccountUpdateProperties {
|
||||
|
||||
/* Flag to indicate enabling/disabling of Per-Region Per-partition autoscale Preview feature on the account */
|
||||
enablePerRegionPerPartitionAutoscale?: boolean;
|
||||
/* Flag to indicate if All Versions and Deletes Change feed feature is enabled on the account */
|
||||
enableAllVersionsAndDeletesChangeFeed?: boolean;
|
||||
}
|
||||
|
||||
/* Parameters for patching Azure Cosmos DB database account properties. */
|
||||
@@ -1216,6 +1222,8 @@ export interface PhysicalPartitionThroughputInfoResource {
|
||||
id: string;
|
||||
/* Throughput of a physical partition */
|
||||
throughput?: number;
|
||||
/* Target throughput of a physical partition */
|
||||
targetThroughput?: number;
|
||||
}
|
||||
|
||||
/* Cosmos DB client encryption key resource object. */
|
||||
@@ -1285,12 +1293,16 @@ export interface SqlContainerResource {
|
||||
/* The configuration for defining Materialized Views. This must be specified only for creating a Materialized View container. */
|
||||
materializedViewDefinition?: MaterializedViewDefinition;
|
||||
|
||||
/* Materialized Views defined on the container. */
|
||||
materializedViews?: MaterializedViewDetails[];
|
||||
|
||||
/* List of computed properties */
|
||||
computedProperties?: ComputedProperty[];
|
||||
|
||||
/* The vector embedding policy for the container. */
|
||||
vectorEmbeddingPolicy?: VectorEmbeddingPolicy;
|
||||
|
||||
/* The FullText policy for the container. */
|
||||
fullTextPolicy?: FullTextPolicy;
|
||||
}
|
||||
|
||||
@@ -1323,6 +1335,14 @@ export interface VectorEmbeddingPolicy {
|
||||
vectorEmbeddings?: VectorEmbedding[];
|
||||
}
|
||||
|
||||
/* Cosmos DB FullText Policy */
|
||||
export interface FullTextPolicy {
|
||||
/* The default language for a full text paths. */
|
||||
defaultLanguage?: string;
|
||||
/* List of FullText Paths */
|
||||
fullTextPaths?: FullTextPath[];
|
||||
}
|
||||
|
||||
/* undocumented */
|
||||
export interface ExcludedPath {
|
||||
/* The path for which the indexing behavior applies to. Index paths typically start with root and end with wildcard (/path/*) */
|
||||
@@ -1361,7 +1381,7 @@ export interface VectorEmbedding {
|
||||
/* The path to the vector field in the document. */
|
||||
path: string;
|
||||
/* Indicates the data type of vector. */
|
||||
dataType: "float16" | "float32" | "uint8" | "int8";
|
||||
dataType: "float32" | "uint8" | "int8";
|
||||
|
||||
/* The distance function to use for distance calculation in between vectors. */
|
||||
distanceFunction: "euclidean" | "cosine" | "dotproduct";
|
||||
@@ -1370,26 +1390,12 @@ export interface VectorEmbedding {
|
||||
dimensions: number;
|
||||
}
|
||||
|
||||
export interface FullTextPolicy {
|
||||
/**
|
||||
* The default language for the full text .
|
||||
*/
|
||||
defaultLanguage: string;
|
||||
/**
|
||||
* The paths to be indexed for full text search.
|
||||
*/
|
||||
fullTextPaths: FullTextPath[];
|
||||
}
|
||||
|
||||
/* Represents the full text path specification. */
|
||||
export interface FullTextPath {
|
||||
/**
|
||||
* The path to be indexed for full text search.
|
||||
*/
|
||||
/* The path to the full text field in the document. */
|
||||
path: string;
|
||||
/**
|
||||
* The language for the full text path.
|
||||
*/
|
||||
language: string;
|
||||
/* The language of the full text field in the document. */
|
||||
language?: string;
|
||||
}
|
||||
|
||||
/* List of composite path */
|
||||
@@ -1493,6 +1499,14 @@ export interface MaterializedViewDefinition {
|
||||
definition: string;
|
||||
}
|
||||
|
||||
/* MaterializedViewDetails, contains Id & _rid fields of materialized view. */
|
||||
export interface MaterializedViewDetails {
|
||||
/* Id field of Materialized container. */
|
||||
id?: string;
|
||||
/* _rid field of Materialized container. */
|
||||
_rid?: string;
|
||||
}
|
||||
|
||||
/* Cosmos DB SQL storedProcedure resource object */
|
||||
export interface SqlStoredProcedureResource {
|
||||
/* Name of the Cosmos DB SQL storedProcedure */
|
||||
|
||||
@@ -64,7 +64,8 @@ import {
|
||||
getMsalInstance,
|
||||
} from "../Utils/AuthorizationUtils";
|
||||
import { isInvalidParentFrameOrigin, shouldProcessMessage } from "../Utils/MessageValidation";
|
||||
import { getReadOnlyKeys, listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||
import { get, getReadOnlyKeys, listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||
import * as Types from "../Utils/arm/generatedClients/cosmos/types";
|
||||
import { applyExplorerBindings } from "../applyExplorerBindings";
|
||||
|
||||
// This hook will create a new instance of Explorer.ts and bind it to the DOM
|
||||
@@ -346,6 +347,14 @@ async function configureHostedWithAAD(config: AAD): Promise<Explorer> {
|
||||
}
|
||||
}
|
||||
try {
|
||||
// TO DO - Remove once we have ARG API support for enableMaterializedViews property
|
||||
const databaseAccount: Types.DatabaseAccountGetResults = await get(
|
||||
subscriptionId,
|
||||
account.resourceGroup,
|
||||
account.name,
|
||||
);
|
||||
config.databaseAccount.properties.enableMaterializedViews = databaseAccount.properties?.enableMaterializedViews;
|
||||
|
||||
updateUserContext({
|
||||
databaseAccount: config.databaseAccount,
|
||||
});
|
||||
|
||||
@@ -103,7 +103,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
.forEach((tab) => tab.onCloseTabButtonClick()),
|
||||
closeTab: (tab: TabsBase): void => {
|
||||
let tabIndex: number;
|
||||
const { activeTab, openedTabs } = get();
|
||||
const { activeTab, openedTabs, openedReactTabs } = get();
|
||||
const updatedTabs = openedTabs.filter((openedTab, index) => {
|
||||
if (tab.tabId === openedTab.tabId) {
|
||||
tabIndex = index;
|
||||
@@ -127,6 +127,10 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
|
||||
set({ openedTabs: updatedTabs });
|
||||
|
||||
if (updatedTabs.length === 0 && openedReactTabs.length > 0) {
|
||||
set({ activeTab: undefined, activeReactTab: openedReactTabs[openedReactTabs.length - 1] });
|
||||
}
|
||||
|
||||
get().persistTabsState();
|
||||
},
|
||||
closeAllNotebookTabs: (hardClose): void => {
|
||||
|
||||
@@ -16,7 +16,7 @@ Results of this file should be checked into the repo.
|
||||
*/
|
||||
|
||||
// CHANGE THESE VALUES TO GENERATE NEW CLIENTS
|
||||
const version = "2024-12-01-preview";
|
||||
const version = "2025-05-01-preview";
|
||||
/* The following are legal options for resourceName but you generally will only use cosmos:
|
||||
"cosmos" | "managedCassandra" | "mongorbac" | "notebook" | "privateEndpointConnection" | "privateLinkResources" |
|
||||
"rbac" | "restorable" | "services" | "dataTransferService"
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<clear />
|
||||
<add name="X-Xss-Protection" value="1; mode=block" />
|
||||
<add name="X-Content-Type-Options" value="nosniff" />
|
||||
<add name="Content-Security-Policy" value="frame-src 'vscode:' frame-ancestors 'self' portal.azure.com *.portal.azure.com portal.azure.us portal.azure.cn portal.microsoftazure.de df.onecloud.azure-test.net *.fabric.microsoft.com *.powerbi.com *.analysis-df.windows.net dataexplorer-preview.azurewebsites.net" />
|
||||
<add name="Content-Security-Policy" value="frame-ancestors 'self' portal.azure.com *.portal.azure.com portal.azure.us portal.azure.cn portal.microsoftazure.de df.onecloud.azure-test.net *.fabric.microsoft.com *.powerbi.com *.analysis-df.windows.net dataexplorer-preview.azurewebsites.net" />
|
||||
</customHeaders>
|
||||
<redirectHeaders>
|
||||
<clear />
|
||||
|
||||
@@ -78,11 +78,18 @@ const typescriptRule = {
|
||||
exclude: /node_modules/,
|
||||
};
|
||||
|
||||
const javascriptRule = {
|
||||
test: /\.m?js$/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
/** @type {(_env: Record<string, string>, argv: Record<string, unknown>) => import("webpack").Configuration} */
|
||||
module.exports = function (_env = {}, argv = {}) {
|
||||
const mode = argv.mode || "development";
|
||||
const rules = [fontRule, lessRule, imagesRule, cssRule, htmlRule, typescriptRule];
|
||||
const rules = [fontRule, lessRule, imagesRule, cssRule, htmlRule, typescriptRule, javascriptRule];
|
||||
const envVars = {
|
||||
GIT_SHA: gitSha,
|
||||
PORT: process.env.PORT || "1234",
|
||||
|
||||
Reference in New Issue
Block a user