mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-29 13:51:49 +00:00
Compare commits
18 Commits
release/ma
...
missing_pk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e8db9b539 | ||
|
|
f94a452a98 | ||
|
|
6ce81099ef | ||
|
|
777e411f4f | ||
|
|
63d4b4f4ef | ||
|
|
eaf9a14e7d | ||
|
|
5997fabcda | ||
|
|
f01d4a5ae2 | ||
|
|
20eeed98e4 | ||
|
|
ac53e1b3b5 | ||
|
|
2cab086268 | ||
|
|
937451d844 | ||
|
|
5dfaa9f0f8 | ||
|
|
05e2d0ac29 | ||
|
|
152c995ec0 | ||
|
|
07c4ca9c50 | ||
|
|
80781f7c8f | ||
|
|
aa39359460 |
@@ -1914,13 +1914,20 @@ input::-webkit-calendar-picker-indicator::after {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs-margin {
|
.nav-tabs-margin {
|
||||||
height: 32px;
|
|
||||||
background-color: #f2f2f2;
|
background-color: #f2f2f2;
|
||||||
|
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
margin-bottom: -0.5px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
// Override the bootstrap defaults here to align with our layout constants.
|
||||||
|
margin-bottom: 0px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
package-lock.json
generated
51
package-lock.json
generated
@@ -86,7 +86,7 @@
|
|||||||
"mkdirp": "1.0.4",
|
"mkdirp": "1.0.4",
|
||||||
"monaco-editor": "0.44.0",
|
"monaco-editor": "0.44.0",
|
||||||
"ms": "2.1.3",
|
"ms": "2.1.3",
|
||||||
"p-retry": "4.6.2",
|
"p-retry": "6.2.1",
|
||||||
"patch-package": "8.0.0",
|
"patch-package": "8.0.0",
|
||||||
"plotly.js-cartesian-dist-min": "1.52.3",
|
"plotly.js-cartesian-dist-min": "1.52.3",
|
||||||
"post-robot": "10.0.42",
|
"post-robot": "10.0.42",
|
||||||
@@ -12662,7 +12662,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/retry": {
|
"node_modules/@types/retry": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz",
|
||||||
|
"integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/sanitize-html": {
|
"node_modules/@types/sanitize-html": {
|
||||||
@@ -21799,6 +21801,18 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-network-error": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-number": {
|
"node_modules/is-number": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -30243,14 +30257,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/p-retry": {
|
"node_modules/p-retry": {
|
||||||
"version": "4.6.2",
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/retry": "0.12.0",
|
"@types/retry": "0.12.2",
|
||||||
|
"is-network-error": "^1.0.0",
|
||||||
"retry": "^0.13.1"
|
"retry": "^0.13.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=16.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/p-try": {
|
"node_modules/p-try": {
|
||||||
@@ -35997,6 +36017,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webpack-dev-server/node_modules/@types/retry": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||||
|
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/ajv": {
|
"node_modules/webpack-dev-server/node_modules/ajv": {
|
||||||
"version": "8.12.0",
|
"version": "8.12.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -36044,6 +36071,20 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webpack-dev-server/node_modules/p-retry": {
|
||||||
|
"version": "4.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
|
||||||
|
"integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/retry": "0.12.0",
|
||||||
|
"retry": "^0.13.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/rimraf": {
|
"node_modules/webpack-dev-server/node_modules/rimraf": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
"mkdirp": "1.0.4",
|
"mkdirp": "1.0.4",
|
||||||
"monaco-editor": "0.44.0",
|
"monaco-editor": "0.44.0",
|
||||||
"ms": "2.1.3",
|
"ms": "2.1.3",
|
||||||
"p-retry": "4.6.2",
|
"p-retry": "6.2.1",
|
||||||
"patch-package": "8.0.0",
|
"patch-package": "8.0.0",
|
||||||
"plotly.js-cartesian-dist-min": "1.52.3",
|
"plotly.js-cartesian-dist-min": "1.52.3",
|
||||||
"post-robot": "10.0.42",
|
"post-robot": "10.0.42",
|
||||||
|
|||||||
37911
preview/package-lock.json
generated
37911
preview/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
* Notebook container related stuff
|
* Notebook container related stuff
|
||||||
*/
|
*/
|
||||||
import { useDialog } from "Explorer/Controls/Dialog";
|
import { useDialog } from "Explorer/Controls/Dialog";
|
||||||
import promiseRetry, { AbortError } from "p-retry";
|
import promiseRetry, { AbortError, Options } from "p-retry";
|
||||||
import { PhoenixClient } from "Phoenix/PhoenixClient";
|
import { PhoenixClient } from "Phoenix/PhoenixClient";
|
||||||
import * as Constants from "../../Common/Constants";
|
import * as Constants from "../../Common/Constants";
|
||||||
import { ConnectionStatusType, HttpHeaders, HttpStatusCodes, Notebook, PoolIdType } from "../../Common/Constants";
|
import { ConnectionStatusType, HttpHeaders, HttpStatusCodes, Notebook, PoolIdType } from "../../Common/Constants";
|
||||||
@@ -19,7 +19,7 @@ export class NotebookContainerClient {
|
|||||||
private clearReconnectionAttemptMessage? = () => {};
|
private clearReconnectionAttemptMessage? = () => {};
|
||||||
private isResettingWorkspace: boolean;
|
private isResettingWorkspace: boolean;
|
||||||
private phoenixClient: PhoenixClient;
|
private phoenixClient: PhoenixClient;
|
||||||
private retryOptions: promiseRetry.Options;
|
private retryOptions: Options;
|
||||||
private scheduleTimerId: NodeJS.Timeout;
|
private scheduleTimerId: NodeJS.Timeout;
|
||||||
|
|
||||||
constructor(private onConnectionLost: () => void) {
|
constructor(private onConnectionLost: () => void) {
|
||||||
|
|||||||
@@ -1028,6 +1028,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectedDocumentId = documentIds[clickedRowIndex as number];
|
const selectedDocumentId = documentIds[clickedRowIndex as number];
|
||||||
|
const originalPartitionKeyValue = selectedDocumentId.partitionKeyValue;
|
||||||
selectedDocumentId.partitionKeyValue = partitionKeyValueArray;
|
selectedDocumentId.partitionKeyValue = partitionKeyValueArray;
|
||||||
|
|
||||||
onExecutionErrorChange(false);
|
onExecutionErrorChange(false);
|
||||||
@@ -1063,9 +1064,14 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
|
|||||||
setColumnDefinitionsFromDocument(documentContent);
|
setColumnDefinitionsFromDocument(documentContent);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
// in case of any kind of failures of accidently changing partition key, restore the original
|
||||||
|
// so that when user navigates away from current document and comes back,
|
||||||
|
// it doesnt fail to load due to using the invalid partition keys
|
||||||
|
selectedDocumentId.partitionKeyValue = originalPartitionKeyValue;
|
||||||
onExecutionErrorChange(true);
|
onExecutionErrorChange(true);
|
||||||
const errorMessage = getErrorMessage(error);
|
const errorMessage = getErrorMessage(error);
|
||||||
useDialog.getState().showOkModalDialog("Update document failed", errorMessage);
|
useDialog.getState().showOkModalDialog("Update document failed", errorMessage);
|
||||||
|
|
||||||
TelemetryProcessor.traceFailure(
|
TelemetryProcessor.traceFailure(
|
||||||
Action.UpdateDocument,
|
Action.UpdateDocument,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules";
|
|||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import FirewallRuleScreenshot from "../../../images/firewallRule.png";
|
import FirewallRuleScreenshot from "../../../images/firewallRule.png";
|
||||||
|
import VcoreFirewallRuleScreenshot from "../../../images/vcoreMongoFirewallRule.png";
|
||||||
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
|
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
@@ -42,7 +43,11 @@ class NotebookTerminalComponentAdapter implements ReactAdapter {
|
|||||||
return (
|
return (
|
||||||
<QuickstartFirewallNotification
|
<QuickstartFirewallNotification
|
||||||
messageType={MessageTypes.OpenPostgresNetworkingBlade}
|
messageType={MessageTypes.OpenPostgresNetworkingBlade}
|
||||||
screenshot={FirewallRuleScreenshot}
|
screenshot={
|
||||||
|
this.kind === ViewModels.TerminalKind.Mongo || this.kind === ViewModels.TerminalKind.VCoreMongo
|
||||||
|
? VcoreFirewallRuleScreenshot
|
||||||
|
: FirewallRuleScreenshot
|
||||||
|
}
|
||||||
shellName={this.getShellNameForDisplay(this.kind)}
|
shellName={this.getShellNameForDisplay(this.kind)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Action } from "Shared/Telemetry/TelemetryConstants";
|
|||||||
import { userContext } from "UserContext";
|
import { userContext } from "UserContext";
|
||||||
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointUtils";
|
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointUtils";
|
||||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||||
import promiseRetry, { AbortError } from "p-retry";
|
import promiseRetry, { AbortError, Options } from "p-retry";
|
||||||
import {
|
import {
|
||||||
Areas,
|
Areas,
|
||||||
ConnectionStatusType,
|
ConnectionStatusType,
|
||||||
@@ -35,21 +35,26 @@ import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
|||||||
export class PhoenixClient {
|
export class PhoenixClient {
|
||||||
private armResourceId: string;
|
private armResourceId: string;
|
||||||
private containerHealthHandler: NodeJS.Timeout;
|
private containerHealthHandler: NodeJS.Timeout;
|
||||||
private retryOptions: promiseRetry.Options = {
|
private retryOptions: Options = {
|
||||||
retries: Notebook.retryAttempts,
|
retries: Notebook.retryAttempts,
|
||||||
maxTimeout: Notebook.retryAttemptDelayMs,
|
maxTimeout: Notebook.retryAttemptDelayMs,
|
||||||
minTimeout: Notebook.retryAttemptDelayMs,
|
minTimeout: Notebook.retryAttemptDelayMs,
|
||||||
};
|
};
|
||||||
|
private abortController: AbortController;
|
||||||
|
private abortSignal: AbortSignal;
|
||||||
|
|
||||||
constructor(armResourceId: string) {
|
constructor(armResourceId: string) {
|
||||||
this.armResourceId = armResourceId;
|
this.armResourceId = armResourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async allocateContainer(provisionData: IProvisionData): Promise<IResponse<IPhoenixServiceInfo>> {
|
public async allocateContainer(provisionData: IProvisionData): Promise<IResponse<IPhoenixServiceInfo>> {
|
||||||
|
this.initializeCancelEventListener();
|
||||||
|
|
||||||
return promiseRetry(() => this.executeContainerAssignmentOperation(provisionData, "allocate"), {
|
return promiseRetry(() => this.executeContainerAssignmentOperation(provisionData, "allocate"), {
|
||||||
retries: 4,
|
retries: 4,
|
||||||
maxTimeout: 20000,
|
maxTimeout: 20000,
|
||||||
minTimeout: 20000,
|
minTimeout: 20000,
|
||||||
|
signal: this.abortSignal,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +275,17 @@ export class PhoenixClient {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private initializeCancelEventListener(): void {
|
||||||
|
this.abortController = new AbortController();
|
||||||
|
this.abortSignal = this.abortController.signal;
|
||||||
|
|
||||||
|
document.addEventListener("keydown", (event: KeyboardEvent) => {
|
||||||
|
if (event.ctrlKey && (event.key === "c" || event.key === "z")) {
|
||||||
|
this.abortController.abort(new AbortError("Request canceled"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public ConvertToForbiddenErrorString(jsonData: IPhoenixError): string {
|
public ConvertToForbiddenErrorString(jsonData: IPhoenixError): string {
|
||||||
const errInfo = jsonData;
|
const errInfo = jsonData;
|
||||||
switch (errInfo?.type) {
|
switch (errInfo?.type) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
} from "@fluentui/react";
|
} from "@fluentui/react";
|
||||||
import { TFunction } from "i18next";
|
import { TFunction } from "i18next";
|
||||||
import promiseRetry, { AbortError } from "p-retry";
|
import promiseRetry, { AbortError, Options } from "p-retry";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { WithTranslation } from "react-i18next";
|
import { WithTranslation } from "react-i18next";
|
||||||
import * as _ from "underscore";
|
import * as _ from "underscore";
|
||||||
@@ -80,7 +80,7 @@ export class SelfServeComponent extends React.Component<SelfServeComponentProps,
|
|||||||
private static readonly defaultRetryIntervalInMs = 30000;
|
private static readonly defaultRetryIntervalInMs = 30000;
|
||||||
private smartUiGeneratorClassName: string;
|
private smartUiGeneratorClassName: string;
|
||||||
private retryIntervalInMs: number;
|
private retryIntervalInMs: number;
|
||||||
private retryOptions: promiseRetry.Options;
|
private retryOptions: Options;
|
||||||
private translationFunction: TFunction;
|
private translationFunction: TFunction;
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
|
|||||||
@@ -197,6 +197,11 @@ export const getPriceMapAndCurrencyCode = async (map: OfferingIdMap): Promise<Pr
|
|||||||
const priceMap = new Map<string, Map<string, number>>();
|
const priceMap = new Map<string, Map<string, number>>();
|
||||||
let billingCurrency;
|
let billingCurrency;
|
||||||
for (const region of map.keys()) {
|
for (const region of map.keys()) {
|
||||||
|
// if no offering id is found for that region, skipping calling price API
|
||||||
|
const subMap = map.get(region);
|
||||||
|
if (!subMap || subMap.size === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const regionPriceMap = new Map<string, number>();
|
const regionPriceMap = new Map<string, number>();
|
||||||
const regionShortName = await getRegionShortName(region);
|
const regionShortName = await getRegionShortName(region);
|
||||||
const requestBody: OfferingIdRequest = {
|
const requestBody: OfferingIdRequest = {
|
||||||
@@ -237,7 +242,7 @@ export const getPriceMapAndCurrencyCode = async (map: OfferingIdMap): Promise<Pr
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
const failureTelemetry = { err, selfServeClassName: SqlX.name };
|
const failureTelemetry = { err, selfServeClassName: SqlX.name };
|
||||||
selfServeTraceFailure(failureTelemetry, getPriceMapAndCurrencyCodeTimestamp);
|
selfServeTraceFailure(failureTelemetry, getPriceMapAndCurrencyCodeTimestamp);
|
||||||
return { priceMap: undefined, billingCurrency: undefined };
|
return { priceMap: new Map<string, Map<string, number>>(), billingCurrency: undefined };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,6 +291,6 @@ export const getOfferingIds = async (regions: Array<RegionItem>): Promise<Offeri
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
const failureTelemetry = { err, selfServeClassName: SqlX.name };
|
const failureTelemetry = { err, selfServeClassName: SqlX.name };
|
||||||
selfServeTraceFailure(failureTelemetry, getOfferingIdsCodeTimestamp);
|
selfServeTraceFailure(failureTelemetry, getOfferingIdsCodeTimestamp);
|
||||||
return undefined;
|
return new Map<string, Map<string, string>>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -227,11 +227,13 @@ const calculateCost = (skuName: string, instanceCount: number): Description => {
|
|||||||
let costPerHour = 0;
|
let costPerHour = 0;
|
||||||
let costBreakdown = "";
|
let costBreakdown = "";
|
||||||
for (const regionItem of regions) {
|
for (const regionItem of regions) {
|
||||||
const incrementalCost = priceMap.get(regionItem.locationName).get(skuName.replace("Cosmos.", ""));
|
const incrementalCost = priceMap?.get(regionItem.locationName)?.get(skuName.replace("Cosmos.", ""));
|
||||||
if (incrementalCost === undefined) {
|
if (incrementalCost === undefined) {
|
||||||
throw new Error(`${regionItem.locationName} not found in price map.`);
|
throw new Error(`${regionItem.locationName} not found in price map.`);
|
||||||
} else if (incrementalCost === 0) {
|
} else if (incrementalCost === 0) {
|
||||||
throw new Error(`${regionItem.locationName} cost per hour = 0`);
|
throw new Error(`${regionItem.locationName} cost per hour = 0`);
|
||||||
|
} else if (currencyCode === undefined) {
|
||||||
|
throw new Error(`Currency code not found in price map.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let regionalInstanceCount = instanceCount;
|
let regionalInstanceCount = instanceCount;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export class JupyterLabAppFactory {
|
|||||||
if (userContext.apiType === "VCoreMongo" && content?.includes("MongoServerError: Invalid key")) {
|
if (userContext.apiType === "VCoreMongo" && content?.includes("MongoServerError: Invalid key")) {
|
||||||
this.restartShell = true;
|
this.restartShell = true;
|
||||||
}
|
}
|
||||||
return content?.includes("cosmosuser@");
|
return content?.includes("cosmosshelluser@");
|
||||||
}
|
}
|
||||||
|
|
||||||
private isMongoShellStarted(content: string | undefined) {
|
private isMongoShellStarted(content: string | undefined) {
|
||||||
@@ -68,7 +68,6 @@ export class JupyterLabAppFactory {
|
|||||||
const session = await manager.startNew();
|
const session = await manager.startNew();
|
||||||
session.messageReceived.connect(async (_, message: IMessage) => {
|
session.messageReceived.connect(async (_, message: IMessage) => {
|
||||||
const content = message.content && message.content[0]?.toString();
|
const content = message.content && message.content[0]?.toString();
|
||||||
|
|
||||||
if (this.checkShellStarted && message.type == "stdout") {
|
if (this.checkShellStarted && message.type == "stdout") {
|
||||||
//Close the terminal tab once the shell closed messages are received
|
//Close the terminal tab once the shell closed messages are received
|
||||||
if (!this.isShellStarted) {
|
if (!this.isShellStarted) {
|
||||||
@@ -114,6 +113,13 @@ export class JupyterLabAppFactory {
|
|||||||
panel.dispose();
|
panel.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Close terminal when Ctrl key is pressed
|
||||||
|
term.node.addEventListener("keydown", (event: KeyboardEvent) => {
|
||||||
|
if (event.ctrlKey) {
|
||||||
|
this.onShellExited(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ describe("Query Utils", () => {
|
|||||||
version: 2,
|
version: 2,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
const generatePartitionKeysForPaths = (paths: string[]): DataModels.PartitionKey => {
|
||||||
|
return {
|
||||||
|
paths: paths,
|
||||||
|
kind: "Hash",
|
||||||
|
version: 2,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
describe("buildDocumentsQueryPartitionProjections()", () => {
|
describe("buildDocumentsQueryPartitionProjections()", () => {
|
||||||
it("should return empty string if partition key is undefined", () => {
|
it("should return empty string if partition key is undefined", () => {
|
||||||
@@ -89,6 +96,18 @@ describe("Query Utils", () => {
|
|||||||
|
|
||||||
expect(query).toContain("c.id");
|
expect(query).toContain("c.id");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should always include {} for any missing partition keys", () => {
|
||||||
|
const query = QueryUtils.buildDocumentsQuery(
|
||||||
|
"",
|
||||||
|
["a", "b", "c"],
|
||||||
|
generatePartitionKeysForPaths(["/a", "/b", "/c"]),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
expect(query).toContain('IIF(IS_DEFINED(c["a"]), c["a"], {})');
|
||||||
|
expect(query).toContain('IIF(IS_DEFINED(c["b"]), c["b"], {})');
|
||||||
|
expect(query).toContain('IIF(IS_DEFINED(c["c"]), c["c"], {})');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("queryPagesUntilContentPresent()", () => {
|
describe("queryPagesUntilContentPresent()", () => {
|
||||||
@@ -201,18 +220,6 @@ describe("Query Utils", () => {
|
|||||||
expect(expectedPartitionKeyValues).toContain(documentContent["Category"]);
|
expect(expectedPartitionKeyValues).toContain(documentContent["Category"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should extract no partition key values in the case nested partition key", () => {
|
|
||||||
const singlePartitionKeyDefinition: PartitionKeyDefinition = {
|
|
||||||
kind: PartitionKeyKind.Hash,
|
|
||||||
paths: ["/Location.type"],
|
|
||||||
};
|
|
||||||
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(
|
|
||||||
documentContent,
|
|
||||||
singlePartitionKeyDefinition,
|
|
||||||
);
|
|
||||||
expect(partitionKeyValues.length).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should extract all partition key values for hierarchical and nested partition keys", () => {
|
it("should extract all partition key values for hierarchical and nested partition keys", () => {
|
||||||
const mixedPartitionKeyDefinition: PartitionKeyDefinition = {
|
const mixedPartitionKeyDefinition: PartitionKeyDefinition = {
|
||||||
kind: PartitionKeyKind.MultiHash,
|
kind: PartitionKeyKind.MultiHash,
|
||||||
@@ -225,5 +232,52 @@ describe("Query Utils", () => {
|
|||||||
expect(partitionKeyValues.length).toBe(2);
|
expect(partitionKeyValues.length).toBe(2);
|
||||||
expect(partitionKeyValues).toEqual(["United States", "Point"]);
|
expect(partitionKeyValues).toEqual(["United States", "Point"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("if any partition key is null or empty string, the partitionKeyValues shall match", () => {
|
||||||
|
const newDocumentContent = {
|
||||||
|
...documentContent,
|
||||||
|
...{
|
||||||
|
Country: null,
|
||||||
|
Location: {
|
||||||
|
type: "",
|
||||||
|
coordinates: [-121.49, 46.206],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mixedPartitionKeyDefinition: PartitionKeyDefinition = {
|
||||||
|
kind: PartitionKeyKind.MultiHash,
|
||||||
|
paths: ["/Country", "/Location/type"],
|
||||||
|
};
|
||||||
|
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(
|
||||||
|
newDocumentContent,
|
||||||
|
mixedPartitionKeyDefinition,
|
||||||
|
);
|
||||||
|
expect(partitionKeyValues.length).toBe(2);
|
||||||
|
expect(partitionKeyValues).toEqual([null, ""]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("if any partition key doesn't exist, it should still set partitionkey value as {}", () => {
|
||||||
|
const newDocumentContent = {
|
||||||
|
...documentContent,
|
||||||
|
...{
|
||||||
|
Country: null,
|
||||||
|
Location: {
|
||||||
|
coordinates: [-121.49, 46.206],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mixedPartitionKeyDefinition: PartitionKeyDefinition = {
|
||||||
|
kind: PartitionKeyKind.MultiHash,
|
||||||
|
paths: ["/Country", "/Location/type"],
|
||||||
|
};
|
||||||
|
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(
|
||||||
|
newDocumentContent,
|
||||||
|
mixedPartitionKeyDefinition,
|
||||||
|
);
|
||||||
|
expect(partitionKeyValues.length).toBe(2);
|
||||||
|
expect(partitionKeyValues).toEqual([null, {}]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,8 +61,9 @@ export function buildDocumentsQueryPartitionProjections(
|
|||||||
projectedProperty += `[${projection}]`;
|
projectedProperty += `[${projection}]`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const fullAccess = `${collectionAlias}${projectedProperty}`;
|
||||||
projections.push(`${collectionAlias}${projectedProperty}`);
|
const wrappedProjection = `IIF(IS_DEFINED(${fullAccess}), ${fullAccess}, {})`;
|
||||||
|
projections.push(wrappedProjection);
|
||||||
}
|
}
|
||||||
|
|
||||||
return projections.join(",");
|
return projections.join(",");
|
||||||
@@ -130,6 +131,8 @@ export const extractPartitionKeyValues = (
|
|||||||
|
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
partitionKeyValues.push(value);
|
partitionKeyValues.push(value);
|
||||||
|
} else {
|
||||||
|
partitionKeyValues.push({});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user