mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-11 05:29:54 +00:00
Compare commits
4 Commits
memory-swr
...
generated-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4fd56ecb0 | ||
|
|
a8eeeebb59 | ||
|
|
abe491f5cd | ||
|
|
2fc15cf322 |
@@ -266,6 +266,10 @@ src/ResourceProvider/ResourceProviderClientFactory.ts
|
|||||||
src/RouteHandlers/RouteHandler.ts
|
src/RouteHandlers/RouteHandler.ts
|
||||||
src/RouteHandlers/TabRouteHandler.test.ts
|
src/RouteHandlers/TabRouteHandler.test.ts
|
||||||
src/RouteHandlers/TabRouteHandler.ts
|
src/RouteHandlers/TabRouteHandler.ts
|
||||||
|
src/Shared/AddCollectionUtility.test.ts
|
||||||
|
src/Shared/AddCollectionUtility.ts
|
||||||
|
src/Shared/AddDatabaseUtility.test.ts
|
||||||
|
src/Shared/AddDatabaseUtility.ts
|
||||||
src/Shared/Constants.ts
|
src/Shared/Constants.ts
|
||||||
src/Shared/DefaultExperienceUtility.test.ts
|
src/Shared/DefaultExperienceUtility.test.ts
|
||||||
src/Shared/DefaultExperienceUtility.ts
|
src/Shared/DefaultExperienceUtility.ts
|
||||||
@@ -275,6 +279,8 @@ src/Shared/StorageUtility.test.ts
|
|||||||
src/Shared/StorageUtility.ts
|
src/Shared/StorageUtility.ts
|
||||||
src/Shared/StringUtility.test.ts
|
src/Shared/StringUtility.test.ts
|
||||||
src/Shared/StringUtility.ts
|
src/Shared/StringUtility.ts
|
||||||
|
src/Shared/Telemetry/TelemetryConstants.ts
|
||||||
|
src/Shared/Telemetry/TelemetryProcessor.ts
|
||||||
src/Shared/appInsights.ts
|
src/Shared/appInsights.ts
|
||||||
src/SparkClusterManager/ArcadiaResourceManager.ts
|
src/SparkClusterManager/ArcadiaResourceManager.ts
|
||||||
src/SparkClusterManager/SparkClusterManager.ts
|
src/SparkClusterManager/SparkClusterManager.ts
|
||||||
@@ -412,5 +418,6 @@ cypress/integration/dataexplorer/SQL/addCollection.spec.ts
|
|||||||
cypress/integration/dataexplorer/TABLE/addCollection.spec.ts
|
cypress/integration/dataexplorer/TABLE/addCollection.spec.ts
|
||||||
cypress/integration/notebook/newNotebook.spec.ts
|
cypress/integration/notebook/newNotebook.spec.ts
|
||||||
cypress/integration/notebook/resourceTree.spec.ts
|
cypress/integration/notebook/resourceTree.spec.ts
|
||||||
|
__mocks__/AddDatabaseUtility.ts
|
||||||
__mocks__/monaco-editor.ts
|
__mocks__/monaco-editor.ts
|
||||||
src/Explorer/Tree/ResourceTreeAdapterForResourceToken.test.tsx
|
src/Explorer/Tree/ResourceTreeAdapterForResourceToken.test.tsx
|
||||||
5
__mocks__/AddDatabaseUtility.ts
Normal file
5
__mocks__/AddDatabaseUtility.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export class AddDbUtilities {
|
||||||
|
createGremlinDatabase(params: any) {
|
||||||
|
return Promise.resolve(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3018,7 +3018,3 @@ settings-pane {
|
|||||||
.italic {
|
.italic {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warningErrorContent a {
|
|
||||||
color: @AccentMediumHigh
|
|
||||||
}
|
|
||||||
706
package-lock.json
generated
706
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@@ -8,7 +8,7 @@
|
|||||||
"@azure/cosmos-language-service": "0.0.4",
|
"@azure/cosmos-language-service": "0.0.4",
|
||||||
"@jupyterlab/services": "4.2.0",
|
"@jupyterlab/services": "4.2.0",
|
||||||
"@jupyterlab/terminal": "1.2.1",
|
"@jupyterlab/terminal": "1.2.1",
|
||||||
"@microsoft/applicationinsights-web": "2.5.8",
|
"@microsoft/applicationinsights-web": "2.5.4",
|
||||||
"@nteract/commutable": "7.1.4",
|
"@nteract/commutable": "7.1.4",
|
||||||
"@nteract/connected-components": "6.7.8",
|
"@nteract/connected-components": "6.7.8",
|
||||||
"@nteract/core": "13.0.0",
|
"@nteract/core": "13.0.0",
|
||||||
@@ -66,13 +66,13 @@
|
|||||||
"mkdirp": "1.0.4",
|
"mkdirp": "1.0.4",
|
||||||
"monaco-editor": "0.15.6",
|
"monaco-editor": "0.15.6",
|
||||||
"object.entries": "1.1.0",
|
"object.entries": "1.1.0",
|
||||||
"office-ui-fabric-react": "7.134.1",
|
"office-ui-fabric-react": "7.121.10",
|
||||||
"p-retry": "4.2.0",
|
"p-retry": "4.2.0",
|
||||||
"plotly.js-cartesian-dist-min": "1.52.3",
|
"plotly.js-cartesian-dist-min": "1.52.3",
|
||||||
"promise-polyfill": "8.1.0",
|
"promise-polyfill": "8.1.0",
|
||||||
"promise.prototype.finally": "3.1.0",
|
"promise.prototype.finally": "3.1.0",
|
||||||
"q": "1.5.1",
|
"q": "1.5.1",
|
||||||
"react": "16.13.1",
|
"react": "16.9.0",
|
||||||
"react-animate-height": "2.0.8",
|
"react-animate-height": "2.0.8",
|
||||||
"react-dnd": "9.4.0",
|
"react-dnd": "9.4.0",
|
||||||
"react-dnd-html5-backend": "9.4.0",
|
"react-dnd-html5-backend": "9.4.0",
|
||||||
@@ -118,8 +118,8 @@
|
|||||||
"@types/text-encoding": "0.0.33",
|
"@types/text-encoding": "0.0.33",
|
||||||
"@types/underscore": "1.7.36",
|
"@types/underscore": "1.7.36",
|
||||||
"@types/webfontloader": "1.6.29",
|
"@types/webfontloader": "1.6.29",
|
||||||
"@typescript-eslint/eslint-plugin": "4.0.1",
|
"@typescript-eslint/eslint-plugin": "3.2.0",
|
||||||
"@typescript-eslint/parser": "4.0.1",
|
"@typescript-eslint/parser": "3.2.0",
|
||||||
"adal-angular": "1.0.15",
|
"adal-angular": "1.0.15",
|
||||||
"axe-puppeteer": "1.1.0",
|
"axe-puppeteer": "1.1.0",
|
||||||
"babel-jest": "24.9.0",
|
"babel-jest": "24.9.0",
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
"enzyme": "3.10.0",
|
"enzyme": "3.10.0",
|
||||||
"enzyme-adapter-react-16": "1.15.1",
|
"enzyme-adapter-react-16": "1.15.1",
|
||||||
"enzyme-to-json": "3.4.3",
|
"enzyme-to-json": "3.4.3",
|
||||||
"eslint": "7.8.1",
|
"eslint": "7.3.1",
|
||||||
"eslint-cli": "1.1.1",
|
"eslint-cli": "1.1.1",
|
||||||
"eslint-plugin-no-null": "1.0.2",
|
"eslint-plugin-no-null": "1.0.2",
|
||||||
"eslint-plugin-prefer-arrow": "1.2.2",
|
"eslint-plugin-prefer-arrow": "1.2.2",
|
||||||
@@ -160,12 +160,11 @@
|
|||||||
"rimraf": "3.0.0",
|
"rimraf": "3.0.0",
|
||||||
"sinon": "3.2.1",
|
"sinon": "3.2.1",
|
||||||
"style-loader": "0.23.0",
|
"style-loader": "0.23.0",
|
||||||
"swr": "0.3.2",
|
|
||||||
"terser-webpack-plugin": "3.0.5",
|
"terser-webpack-plugin": "3.0.5",
|
||||||
"ts-loader": "6.2.2",
|
"ts-loader": "6.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
"tslint-microsoft-contrib": "6.0.0",
|
"tslint-microsoft-contrib": "6.0.0",
|
||||||
"typescript": "4.0.2",
|
"typescript": "3.9.6",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"webpack": "4.43.0",
|
"webpack": "4.43.0",
|
||||||
"webpack-bundle-analyzer": "3.6.1",
|
"webpack-bundle-analyzer": "3.6.1",
|
||||||
|
|||||||
@@ -5,7 +5,14 @@ import { Collection } from "../Contracts/ViewModels";
|
|||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||||
import { updateUserContext } from "../UserContext";
|
import { updateUserContext } from "../UserContext";
|
||||||
import { deleteDocument, getEndpoint, queryDocuments, readDocument, updateDocument } from "./MongoProxyClient";
|
import {
|
||||||
|
deleteDocument,
|
||||||
|
getEndpoint,
|
||||||
|
queryDocuments,
|
||||||
|
readDocument,
|
||||||
|
updateDocument,
|
||||||
|
_createMongoCollectionWithARM
|
||||||
|
} from "./MongoProxyClient";
|
||||||
jest.mock("../ResourceProvider/ResourceProviderClient.ts");
|
jest.mock("../ResourceProvider/ResourceProviderClient.ts");
|
||||||
|
|
||||||
const databaseId = "testDB";
|
const databaseId = "testDB";
|
||||||
@@ -253,4 +260,58 @@ describe("MongoProxyClient", () => {
|
|||||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("createMongoCollectionWithARM", () => {
|
||||||
|
it("should create a collection with autopilot when autopilot is selected + shared throughput is false", () => {
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
const properties = {
|
||||||
|
pk: "state",
|
||||||
|
coll: "abc-collection",
|
||||||
|
cd: true,
|
||||||
|
db: "a1-db",
|
||||||
|
st: false,
|
||||||
|
sid: "a2",
|
||||||
|
rg: "c1",
|
||||||
|
dba: "main",
|
||||||
|
is: false
|
||||||
|
};
|
||||||
|
_createMongoCollectionWithARM("management.azure.com", properties, { "x-ms-cosmos-offer-autopilot-tier": "1" });
|
||||||
|
expect(resourceProviderClientPutAsyncSpy).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a2/resourceGroups/c1/providers/Microsoft.DocumentDB/databaseAccounts/foo/mongodbDatabases/a1-db/collections/abc-collection",
|
||||||
|
"2020-04-01",
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
options: { "x-ms-cosmos-offer-autopilot-tier": "1" },
|
||||||
|
resource: { id: "abc-collection" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("should create a collection with provisioned throughput when provisioned throughput is selected + shared throughput is false", () => {
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
const properties = {
|
||||||
|
pk: "state",
|
||||||
|
coll: "abc-collection",
|
||||||
|
cd: true,
|
||||||
|
db: "a1-db",
|
||||||
|
st: false,
|
||||||
|
sid: "a2",
|
||||||
|
rg: "c1",
|
||||||
|
dba: "main",
|
||||||
|
is: false,
|
||||||
|
offerThroughput: 400
|
||||||
|
};
|
||||||
|
_createMongoCollectionWithARM("management.azure.com", properties, undefined);
|
||||||
|
expect(resourceProviderClientPutAsyncSpy).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a2/resourceGroups/c1/providers/Microsoft.DocumentDB/databaseAccounts/foo/mongodbDatabases/a1-db/collections/abc-collection",
|
||||||
|
"2020-04-01",
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
options: { throughput: "400" },
|
||||||
|
resource: { id: "abc-collection" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import { Constants as CosmosSDKConstants } from "@azure/cosmos";
|
import { Constants as CosmosSDKConstants } from "@azure/cosmos";
|
||||||
import queryString from "querystring";
|
import queryString from "querystring";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
|
import * as DataExplorerConstants from "../Common/Constants";
|
||||||
import { configContext } from "../ConfigContext";
|
import { configContext } from "../ConfigContext";
|
||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
import { Collection } from "../Contracts/ViewModels";
|
import { Collection } from "../Contracts/ViewModels";
|
||||||
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
|
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||||
|
import { AddDbUtilities } from "../Shared/AddDatabaseUtility";
|
||||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
@@ -327,6 +330,48 @@ export function createMongoCollectionWithProxy(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createMongoCollectionWithARM(
|
||||||
|
armEndpoint: string,
|
||||||
|
databaseId: string,
|
||||||
|
analyticalStorageTtl: number,
|
||||||
|
collectionId: string,
|
||||||
|
offerThroughput: number,
|
||||||
|
shardKey: string,
|
||||||
|
createDatabase: boolean,
|
||||||
|
sharedThroughput: boolean,
|
||||||
|
isSharded: boolean,
|
||||||
|
additionalOptions?: DataModels.RpOptions
|
||||||
|
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||||
|
const databaseAccount = userContext.databaseAccount;
|
||||||
|
const params: DataModels.MongoParameters = {
|
||||||
|
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,
|
||||||
|
db: databaseId,
|
||||||
|
coll: collectionId,
|
||||||
|
pk: shardKey,
|
||||||
|
offerThroughput,
|
||||||
|
cd: createDatabase,
|
||||||
|
st: sharedThroughput,
|
||||||
|
is: isSharded,
|
||||||
|
rid: "",
|
||||||
|
rtype: "colls",
|
||||||
|
sid: userContext.subscriptionId,
|
||||||
|
rg: userContext.resourceGroup,
|
||||||
|
dba: databaseAccount.name,
|
||||||
|
analyticalStorageTtl
|
||||||
|
};
|
||||||
|
|
||||||
|
if (createDatabase) {
|
||||||
|
return AddDbUtilities.createMongoDatabaseWithARM(
|
||||||
|
armEndpoint,
|
||||||
|
params,
|
||||||
|
sharedThroughput ? additionalOptions : {}
|
||||||
|
).then(() => {
|
||||||
|
return _createMongoCollectionWithARM(armEndpoint, params, sharedThroughput ? {} : additionalOptions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return _createMongoCollectionWithARM(armEndpoint, params, additionalOptions);
|
||||||
|
}
|
||||||
|
|
||||||
export function getEndpoint(databaseAccount: DataModels.DatabaseAccount): string {
|
export function getEndpoint(databaseAccount: DataModels.DatabaseAccount): string {
|
||||||
const serverId = window.dataExplorer.serverId();
|
const serverId = window.dataExplorer.serverId();
|
||||||
const extensionEndpoint = window.dataExplorer.extensionEndpoint();
|
const extensionEndpoint = window.dataExplorer.extensionEndpoint();
|
||||||
@@ -359,3 +404,46 @@ async function errorHandling(response: Response, action: string, params: unknown
|
|||||||
export function getARMCreateCollectionEndpoint(params: DataModels.MongoParameters): string {
|
export function getARMCreateCollectionEndpoint(params: DataModels.MongoParameters): string {
|
||||||
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/mongodbDatabases/${params.db}/collections/${params.coll}`;
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/mongodbDatabases/${params.db}/collections/${params.coll}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function _createMongoCollectionWithARM(
|
||||||
|
armEndpoint: string,
|
||||||
|
params: DataModels.MongoParameters,
|
||||||
|
rpOptions: DataModels.RpOptions
|
||||||
|
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||||
|
const rpPayloadToCreateCollection: DataModels.MongoCreationRequest = {
|
||||||
|
properties: {
|
||||||
|
resource: {
|
||||||
|
id: params.coll
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.is) {
|
||||||
|
rpPayloadToCreateCollection.properties.resource["shardKey"] = { [params.pk]: "Hash" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.st) {
|
||||||
|
if (rpOptions) {
|
||||||
|
rpPayloadToCreateCollection.properties.options = rpOptions;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateCollection.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.analyticalStorageTtl) {
|
||||||
|
rpPayloadToCreateCollection.properties.resource.analyticalStorageTtl = params.analyticalStorageTtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new ResourceProviderClient<DataModels.CreateCollectionWithRpResponse>(armEndpoint).putAsync(
|
||||||
|
getARMCreateCollectionEndpoint(params),
|
||||||
|
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||||
|
rpPayloadToCreateCollection
|
||||||
|
);
|
||||||
|
} catch (response) {
|
||||||
|
errorHandling(response, "creating collection", undefined);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,26 +6,23 @@ import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/Contai
|
|||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||||
import {
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
createUpdateSqlContainer,
|
|
||||||
getSqlContainer
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable
|
getCassandraTable
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBCollection,
|
createUpdateMongoDBCollection,
|
||||||
getMongoDBCollection
|
getMongoDBCollection
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinGraph,
|
createUpdateGremlinGraph,
|
||||||
getGremlinGraph
|
getGremlinGraph
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logError } from "../Logger";
|
import { logError } from "../Logger";
|
||||||
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
||||||
|
|||||||
@@ -9,24 +9,21 @@ import {
|
|||||||
MongoDBDatabaseCreateUpdateParameters,
|
MongoDBDatabaseCreateUpdateParameters,
|
||||||
SqlDatabaseCreateUpdateParameters,
|
SqlDatabaseCreateUpdateParameters,
|
||||||
CreateUpdateOptions
|
CreateUpdateOptions
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import {
|
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
createUpdateSqlDatabase,
|
|
||||||
getSqlDatabase
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraKeyspace,
|
createUpdateCassandraKeyspace,
|
||||||
getCassandraKeyspace
|
getCassandraKeyspace
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBDatabase,
|
createUpdateMongoDBDatabase,
|
||||||
getMongoDBDatabase
|
getMongoDBDatabase
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinDatabase,
|
createUpdateGremlinDatabase,
|
||||||
getGremlinDatabase
|
getGremlinDatabase
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logError } from "../Logger";
|
import { logError } from "../Logger";
|
||||||
import { refreshCachedOffers, refreshCachedResources } from "../DataAccessUtilityBase";
|
import { refreshCachedOffers, refreshCachedResources } from "../DataAccessUtilityBase";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logError } from "../Logger";
|
import { logError } from "../Logger";
|
||||||
import { sendNotificationForError } from "./sendNotificationForError";
|
import { sendNotificationForError } from "./sendNotificationForError";
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import * as DataModels from "../../Contracts/DataModels";
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logError } from "../Logger";
|
import { logError } from "../Logger";
|
||||||
import { sendNotificationForError } from "./sendNotificationForError";
|
import { sendNotificationForError } from "./sendNotificationForError";
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import * as DataModels from "../../Contracts/DataModels";
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress, logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logError } from "../Logger";
|
import { logError } from "../Logger";
|
||||||
import { sendNotificationForError } from "./sendNotificationForError";
|
import { sendNotificationForError } from "./sendNotificationForError";
|
||||||
|
|||||||
@@ -6,26 +6,23 @@ import {
|
|||||||
ExtendedResourceProperties,
|
ExtendedResourceProperties,
|
||||||
SqlContainerCreateUpdateParameters,
|
SqlContainerCreateUpdateParameters,
|
||||||
SqlContainerResource
|
SqlContainerResource
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import {
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
createUpdateSqlContainer,
|
|
||||||
getSqlContainer
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable
|
getCassandraTable
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBCollection,
|
createUpdateMongoDBCollection,
|
||||||
getMongoDBCollection
|
getMongoDBCollection
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinGraph,
|
createUpdateGremlinGraph,
|
||||||
getGremlinGraph
|
getGremlinGraph
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01-cosmos-db/tableResources";
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logError } from "../Logger";
|
import { logError } from "../Logger";
|
||||||
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
import { refreshCachedResources } from "../DataAccessUtilityBase";
|
||||||
|
|||||||
@@ -709,6 +709,11 @@ export interface SparkPool extends ArmResource {
|
|||||||
properties: SparkPoolProperties;
|
properties: SparkPoolProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MemoryUsageInfo {
|
||||||
|
freeKB: number;
|
||||||
|
totalKB: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface resourceTokenConnectionStringProperties {
|
export interface resourceTokenConnectionStringProperties {
|
||||||
accountEndpoint: string;
|
accountEndpoint: string;
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { StringUtils } from "../../../Utils/StringUtils";
|
import { StringUtils } from "../../../Utils/StringUtils";
|
||||||
import { KeyCodes } from "../../../Common/Constants";
|
import { KeyCodes } from "../../../Common/Constants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import CollapseChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
|
import CollapseChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
|
||||||
|
|
||||||
|
|||||||
@@ -265,9 +265,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"buttonTextDisabled": "#a19f9d",
|
"buttonTextDisabled": "#a19f9d",
|
||||||
"buttonTextHovered": "#201f1e",
|
"buttonTextHovered": "#201f1e",
|
||||||
"buttonTextPressed": "#201f1e",
|
"buttonTextPressed": "#201f1e",
|
||||||
"cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardStandoutBackground": "#ffffff",
|
|
||||||
"defaultStateBackground": "#faf9f8",
|
"defaultStateBackground": "#faf9f8",
|
||||||
"disabledBackground": "#f3f2f1",
|
"disabledBackground": "#f3f2f1",
|
||||||
"disabledBodySubtext": "#c8c6c4",
|
"disabledBodySubtext": "#c8c6c4",
|
||||||
@@ -607,9 +604,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"buttonTextDisabled": "#a19f9d",
|
"buttonTextDisabled": "#a19f9d",
|
||||||
"buttonTextHovered": "#201f1e",
|
"buttonTextHovered": "#201f1e",
|
||||||
"buttonTextPressed": "#201f1e",
|
"buttonTextPressed": "#201f1e",
|
||||||
"cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardStandoutBackground": "#ffffff",
|
|
||||||
"defaultStateBackground": "#faf9f8",
|
"defaultStateBackground": "#faf9f8",
|
||||||
"disabledBackground": "#f3f2f1",
|
"disabledBackground": "#f3f2f1",
|
||||||
"disabledBodySubtext": "#c8c6c4",
|
"disabledBodySubtext": "#c8c6c4",
|
||||||
@@ -1003,9 +997,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"buttonTextDisabled": "#a19f9d",
|
"buttonTextDisabled": "#a19f9d",
|
||||||
"buttonTextHovered": "#201f1e",
|
"buttonTextHovered": "#201f1e",
|
||||||
"buttonTextPressed": "#201f1e",
|
"buttonTextPressed": "#201f1e",
|
||||||
"cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardStandoutBackground": "#ffffff",
|
|
||||||
"defaultStateBackground": "#faf9f8",
|
"defaultStateBackground": "#faf9f8",
|
||||||
"disabledBackground": "#f3f2f1",
|
"disabledBackground": "#f3f2f1",
|
||||||
"disabledBodySubtext": "#c8c6c4",
|
"disabledBodySubtext": "#c8c6c4",
|
||||||
@@ -1122,11 +1113,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
},
|
},
|
||||||
"iconDisabled": Object {
|
"iconDisabled": Object {
|
||||||
"color": "#a19f9d",
|
"color": "#a19f9d",
|
||||||
"selectors": Object {
|
|
||||||
"@media screen and (-ms-high-contrast: active)": Object {
|
|
||||||
"color": "GrayText",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"label": Array [
|
"label": Array [
|
||||||
Object {
|
Object {
|
||||||
@@ -1148,11 +1134,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
},
|
},
|
||||||
"menuIconDisabled": Object {
|
"menuIconDisabled": Object {
|
||||||
"color": "#a19f9d",
|
"color": "#a19f9d",
|
||||||
"selectors": Object {
|
|
||||||
"@media screen and (-ms-high-contrast: active)": Object {
|
|
||||||
"color": "GrayText",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"root": Array [
|
"root": Array [
|
||||||
Object {
|
Object {
|
||||||
@@ -1169,6 +1150,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"right": 2,
|
"right": 2,
|
||||||
"selectors": Object {
|
"selectors": Object {
|
||||||
"@media screen and (-ms-high-contrast: active)": Object {
|
"@media screen and (-ms-high-contrast: active)": Object {
|
||||||
|
"border": "none",
|
||||||
"bottom": -2,
|
"bottom": -2,
|
||||||
"left": -2,
|
"left": -2,
|
||||||
"outlineColor": "ButtonText",
|
"outlineColor": "ButtonText",
|
||||||
@@ -1248,6 +1230,7 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"right": 2,
|
"right": 2,
|
||||||
"selectors": Object {
|
"selectors": Object {
|
||||||
"@media screen and (-ms-high-contrast: active)": Object {
|
"@media screen and (-ms-high-contrast: active)": Object {
|
||||||
|
"border": "none",
|
||||||
"bottom": -2,
|
"bottom": -2,
|
||||||
"left": -2,
|
"left": -2,
|
||||||
"outlineColor": "ButtonText",
|
"outlineColor": "ButtonText",
|
||||||
@@ -1276,6 +1259,10 @@ exports[`test render renders with filters 1`] = `
|
|||||||
":hover": Object {
|
":hover": Object {
|
||||||
"outline": 0,
|
"outline": 0,
|
||||||
},
|
},
|
||||||
|
"@media screen and (-ms-high-contrast: active)": Object {
|
||||||
|
"borderColor": "grayText",
|
||||||
|
"color": "grayText",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
@@ -1375,21 +1362,13 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"selectors": Object {
|
"selectors": Object {
|
||||||
"@media screen and (-ms-high-contrast: active)": Object {
|
"@media screen and (-ms-high-contrast: active)": Object {
|
||||||
"MsHighContrastAdjust": "none",
|
"MsHighContrastAdjust": "none",
|
||||||
"backgroundColor": "Window",
|
"backgroundColor": "WindowText",
|
||||||
"border": "1px solid WindowText",
|
"color": "Window",
|
||||||
"borderRightWidth": "0",
|
|
||||||
"color": "WindowText",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
".ms-Button--primary + .ms-Button": Object {
|
".ms-Button--primary + .ms-Button": Object {
|
||||||
"border": "none",
|
"border": "none",
|
||||||
"selectors": Object {
|
|
||||||
"@media screen and (-ms-high-contrast: active)": Object {
|
|
||||||
"border": "1px solid WindowText",
|
|
||||||
"borderLeftWidth": "0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1429,9 +1408,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"borderColor": "GrayText",
|
"borderColor": "GrayText",
|
||||||
"color": "GrayText",
|
"color": "GrayText",
|
||||||
},
|
},
|
||||||
"@media screen and (forced-colors: active)": Object {
|
|
||||||
"forcedColorAdjust": "none",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"splitButtonContainerFocused": Object {
|
"splitButtonContainerFocused": Object {
|
||||||
@@ -1578,13 +1554,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
".ms-Button-menuIcon": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
"@media screen and (-ms-high-contrast: active)": Object {
|
|
||||||
"color": "GrayText",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
":hover": Object {
|
":hover": Object {
|
||||||
"cursor": "default",
|
"cursor": "default",
|
||||||
},
|
},
|
||||||
@@ -1806,9 +1775,6 @@ exports[`test render renders with filters 1`] = `
|
|||||||
"buttonTextDisabled": "#a19f9d",
|
"buttonTextDisabled": "#a19f9d",
|
||||||
"buttonTextHovered": "#201f1e",
|
"buttonTextHovered": "#201f1e",
|
||||||
"buttonTextPressed": "#201f1e",
|
"buttonTextPressed": "#201f1e",
|
||||||
"cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardStandoutBackground": "#ffffff",
|
|
||||||
"defaultStateBackground": "#faf9f8",
|
"defaultStateBackground": "#faf9f8",
|
||||||
"disabledBackground": "#f3f2f1",
|
"disabledBackground": "#f3f2f1",
|
||||||
"disabledBodySubtext": "#c8c6c4",
|
"disabledBodySubtext": "#c8c6c4",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { RepoListItem } from "./GitHubReposComponent";
|
|||||||
import { ChildrenMargin } from "./GitHubStyleConstants";
|
import { ChildrenMargin } from "./GitHubStyleConstants";
|
||||||
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
||||||
import { IGitHubRepo } from "../../../GitHub/GitHubClient";
|
import { IGitHubRepo } from "../../../GitHub/GitHubClient";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import UrlUtility from "../../../Common/UrlUtility";
|
import UrlUtility from "../../../Common/UrlUtility";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
} from "office-ui-fabric-react/lib/utilities/selection/index";
|
} from "office-ui-fabric-react/lib/utilities/selection/index";
|
||||||
import { StyleConstants } from "../../../Common/Constants";
|
import { StyleConstants } from "../../../Common/Constants";
|
||||||
import { TextField, ITextFieldProps, ITextField } from "office-ui-fabric-react/lib/TextField";
|
import { TextField, ITextFieldProps, ITextField } from "office-ui-fabric-react/lib/TextField";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
|
||||||
import SaveQueryBannerIcon from "../../../../images/save_query_banner.png";
|
import SaveQueryBannerIcon from "../../../../images/save_query_banner.png";
|
||||||
import { QueriesClient } from "../../../Common/QueriesClient";
|
import { QueriesClient } from "../../../Common/QueriesClient";
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import NewVertexPane from "./Panes/NewVertexPane";
|
|||||||
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
|
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
|
||||||
import Q from "q";
|
import Q from "q";
|
||||||
import ResourceTokenCollection from "./Tree/ResourceTokenCollection";
|
import ResourceTokenCollection from "./Tree/ResourceTokenCollection";
|
||||||
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
||||||
import TerminalTab from "./Tabs/TerminalTab";
|
import TerminalTab from "./Tabs/TerminalTab";
|
||||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||||
import { ActionContracts, MessageTypes } from "../Contracts/ExplorerContracts";
|
import { ActionContracts, MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
@@ -243,6 +243,7 @@ export default class Explorer {
|
|||||||
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
||||||
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
||||||
public isSynapseLinkUpdating: ko.Observable<boolean>;
|
public isSynapseLinkUpdating: ko.Observable<boolean>;
|
||||||
|
public memoryUsageInfo: ko.Observable<DataModels.MemoryUsageInfo>;
|
||||||
public notebookManager?: any; // This is dynamically loaded
|
public notebookManager?: any; // This is dynamically loaded
|
||||||
|
|
||||||
private _panes: ContextualPaneBase[] = [];
|
private _panes: ContextualPaneBase[] = [];
|
||||||
@@ -373,6 +374,7 @@ export default class Explorer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>();
|
||||||
this.notificationsClient = options.notificationsClient;
|
this.notificationsClient = options.notificationsClient;
|
||||||
this.isEmulator = options.isEmulator;
|
this.isEmulator = options.isEmulator;
|
||||||
|
|
||||||
@@ -3115,6 +3117,12 @@ export default class Explorer {
|
|||||||
} else {
|
} else {
|
||||||
loadingTitle.innerHTML = title;
|
loadingTitle.innerHTML = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TelemetryProcessor.trace(
|
||||||
|
Action.LoadingStatus,
|
||||||
|
ActionModifiers.Mark,
|
||||||
|
title !== "Welcome to Azure Cosmos DB" ? `Title: ${title}, Text: ${text}` : text
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _openSetupNotebooksPaneForQuickstart(): void {
|
private _openSetupNotebooksPaneForQuickstart(): void {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { GraphConfig } from "../../Tabs/GraphTab";
|
|||||||
import { EditorReact } from "../../Controls/Editor/EditorReact";
|
import { EditorReact } from "../../Controls/Editor/EditorReact";
|
||||||
import LoadGraphIcon from "../../../../images/LoadGraph.png";
|
import LoadGraphIcon from "../../../../images/LoadGraph.png";
|
||||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { InputProperty } from "../../../Contracts/ViewModels";
|
import { InputProperty } from "../../../Contracts/ViewModels";
|
||||||
import { QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
|
import { QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
|
||||||
|
|||||||
@@ -82,7 +82,9 @@ export class CommandBarComponentAdapter implements ReactAdapter {
|
|||||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||||
|
|
||||||
if (this.isNotebookTabActive()) {
|
if (this.isNotebookTabActive()) {
|
||||||
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
|
uiFabricControlButtons.unshift(
|
||||||
|
CommandBarUtil.createMemoryTracker("memoryTracker", this.container.memoryUsageInfo)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as ViewModels from "../../../Contracts/ViewModels";
|
|||||||
import { PlatformType } from "../../../PlatformType";
|
import { PlatformType } from "../../../PlatformType";
|
||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { Areas } from "../../../Common/Constants";
|
import { Areas } from "../../../Common/Constants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
|
||||||
import AddDatabaseIcon from "../../../../images/AddDatabase.svg";
|
import AddDatabaseIcon from "../../../../images/AddDatabase.svg";
|
||||||
import AddCollectionIcon from "../../../../images/AddCollection.svg";
|
import AddCollectionIcon from "../../../../images/AddCollection.svg";
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
import _ from "underscore";
|
||||||
import { Dropdown, IDropdownOption, IDropdownStyles } from "office-ui-fabric-react/lib/Dropdown";
|
import * as React from "react";
|
||||||
|
import { Observable } from "knockout";
|
||||||
import { IconType } from "office-ui-fabric-react/lib/Icon";
|
import { IconType } from "office-ui-fabric-react/lib/Icon";
|
||||||
import { IComponentAsProps } from "office-ui-fabric-react/lib/Utilities";
|
import { IComponentAsProps } from "office-ui-fabric-react/lib/Utilities";
|
||||||
import * as React from "react";
|
|
||||||
import _ from "underscore";
|
|
||||||
import ChevronDownIcon from "../../../../images/Chevron_down.svg";
|
|
||||||
import { StyleConstants } from "../../../Common/Constants";
|
import { StyleConstants } from "../../../Common/Constants";
|
||||||
import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker";
|
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||||
|
import { Dropdown, IDropdownStyles, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||||
|
import ChevronDownIcon from "../../../../images/Chevron_down.svg";
|
||||||
|
import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker";
|
||||||
import { MemoryTrackerComponent } from "./MemoryTrackerComponent";
|
import { MemoryTrackerComponent } from "./MemoryTrackerComponent";
|
||||||
|
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for CommandBar
|
* Utilities for CommandBar
|
||||||
@@ -176,10 +178,10 @@ export class CommandBarUtil {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createMemoryTracker(key: string): ICommandBarItemProps {
|
public static createMemoryTracker(key: string, memoryUsageInfo: Observable<MemoryUsageInfo>): ICommandBarItemProps {
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
onRender: () => <MemoryTrackerComponent />
|
onRender: () => <MemoryTrackerComponent memoryUsageInfo={memoryUsageInfo} />
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,50 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
import * as React from "react";
|
||||||
import useSWR from "swr";
|
import { Observable, Subscription } from "knockout";
|
||||||
|
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||||
import { ProgressIndicator } from "office-ui-fabric-react/lib/ProgressIndicator";
|
import { ProgressIndicator } from "office-ui-fabric-react/lib/ProgressIndicator";
|
||||||
import { Spinner, SpinnerSize } from "office-ui-fabric-react/lib/Spinner";
|
import { Spinner, SpinnerSize } from "office-ui-fabric-react/lib/Spinner";
|
||||||
import { Stack } from "office-ui-fabric-react/lib/Stack";
|
import { Stack } from "office-ui-fabric-react/lib/Stack";
|
||||||
import { listConnectionInfo } from "../../../Utils/arm/generatedClients/2020-04-01-notebook/notebookWorkspaces";
|
|
||||||
import { NotebookWorkspaceConnectionInfoResult } from "../../../Utils/arm/generatedClients/2020-04-01-notebook/types";
|
|
||||||
import { userContext } from "../../../UserContext";
|
|
||||||
|
|
||||||
export interface MemoryUsageInfo {
|
interface MemoryTrackerProps {
|
||||||
total: number;
|
memoryUsageInfo: Observable<MemoryUsageInfo>;
|
||||||
free: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const kbInGB = 1048576;
|
export class MemoryTrackerComponent extends React.Component<MemoryTrackerProps> {
|
||||||
|
private memoryUsageInfoSubscription: Subscription;
|
||||||
|
|
||||||
const fetchMemoryInfo = async (_key: unknown, connectionInfo: NotebookWorkspaceConnectionInfoResult) => {
|
public componentDidMount(): void {
|
||||||
const response = await fetch(`${connectionInfo.notebookServerEndpoint}/api/metrics/memory`, {
|
this.memoryUsageInfoSubscription = this.props.memoryUsageInfo.subscribe(() => {
|
||||||
method: "GET",
|
this.forceUpdate();
|
||||||
headers: {
|
});
|
||||||
Authorization: `Token ${connectionInfo.authToken}`,
|
|
||||||
"content-type": "application/json"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(await response.text());
|
|
||||||
}
|
}
|
||||||
const memoryUsageInfo = (await response.json()) as MemoryUsageInfo;
|
|
||||||
return {
|
|
||||||
totalKB: memoryUsageInfo.total,
|
|
||||||
freeKB: memoryUsageInfo.free
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MemoryTrackerComponent: FunctionComponent = () => {
|
public componentWillUnmount(): void {
|
||||||
const { data: connectionInfo } = useSWR(
|
this.memoryUsageInfoSubscription && this.memoryUsageInfoSubscription.dispose();
|
||||||
[
|
}
|
||||||
"notebooksConnectionInfo",
|
|
||||||
userContext.subscriptionId,
|
public render(): JSX.Element {
|
||||||
userContext.resourceGroup,
|
const memoryUsageInfo: MemoryUsageInfo = this.props.memoryUsageInfo();
|
||||||
userContext.databaseAccount.name,
|
if (!memoryUsageInfo) {
|
||||||
"default"
|
return (
|
||||||
],
|
<Stack className="memoryTrackerContainer" horizontal>
|
||||||
(_key, subscriptionId, resourceGroup, accountName, workspace) =>
|
<span>Memory</span>
|
||||||
listConnectionInfo(subscriptionId, resourceGroup, accountName, workspace)
|
<Spinner size={SpinnerSize.medium} />
|
||||||
);
|
</Stack>
|
||||||
const { data } = useSWR(connectionInfo ? ["memoryUsage", connectionInfo] : null, fetchMemoryInfo, {
|
);
|
||||||
refreshInterval: 2000
|
}
|
||||||
});
|
|
||||||
|
const totalGB = memoryUsageInfo.totalKB / 1048576;
|
||||||
|
const usedGB = totalGB - memoryUsageInfo.freeKB / 1048576;
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
return (
|
return (
|
||||||
<Stack className="memoryTrackerContainer" horizontal>
|
<Stack className="memoryTrackerContainer" horizontal>
|
||||||
<span>Memory</span>
|
<span>Memory</span>
|
||||||
<Spinner size={SpinnerSize.medium} />
|
<ProgressIndicator
|
||||||
|
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
||||||
|
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
||||||
|
percentComplete={usedGB / totalGB}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const totalGB = data.totalKB / kbInGB;
|
}
|
||||||
const usedGB = totalGB - data.freeKB / kbInGB;
|
|
||||||
return (
|
|
||||||
<Stack className="memoryTrackerContainer" horizontal>
|
|
||||||
<span>Memory</span>
|
|
||||||
<ProgressIndicator
|
|
||||||
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
|
||||||
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
|
||||||
percentComplete={usedGB / totalGB}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import { Store, AnyAction, MiddlewareAPI, Middleware, Dispatch } from "redux";
|
|||||||
import configureStore from "./NotebookComponent/store";
|
import configureStore from "./NotebookComponent/store";
|
||||||
|
|
||||||
import { Notification } from "react-notification-system";
|
import { Notification } from "react-notification-system";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
|
||||||
export type KernelSpecsDisplay = { name: string; displayName: string };
|
export type KernelSpecsDisplay = { name: string; displayName: string };
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import * as Constants from "../../../Common/Constants";
|
|||||||
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import * as CdbActions from "./actions";
|
import * as CdbActions from "./actions";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action as TelemetryAction } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action as TelemetryAction } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { CdbAppState } from "./types";
|
import { CdbAppState } from "./types";
|
||||||
import { decryptJWTToken } from "../../../Utils/AuthorizationUtils";
|
import { decryptJWTToken } from "../../../Utils/AuthorizationUtils";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { actions, CoreRecord, reducers as nteractReducers } from "@nteract/core";
|
import { actions, CoreRecord, reducers as nteractReducers } from "@nteract/core";
|
||||||
import { Action } from "redux";
|
import { Action } from "redux";
|
||||||
import { Areas } from "../../../Common/Constants";
|
import { Areas } from "../../../Common/Constants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as cdbActions from "./actions";
|
import * as cdbActions from "./actions";
|
||||||
import { CdbRecord } from "./types";
|
import { CdbRecord } from "./types";
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,89 @@
|
|||||||
* Notebook container related stuff
|
* Notebook container related stuff
|
||||||
*/
|
*/
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import * as Constants from "../../Common/Constants";
|
||||||
|
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
import * as Logger from "../../Common/Logger";
|
import * as Logger from "../../Common/Logger";
|
||||||
|
|
||||||
export class NotebookContainerClient {
|
export class NotebookContainerClient {
|
||||||
private reconnectingNotificationId: string;
|
private reconnectingNotificationId: string;
|
||||||
private isResettingWorkspace: boolean;
|
private isResettingWorkspace: boolean;
|
||||||
|
|
||||||
constructor(private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>) {}
|
constructor(
|
||||||
|
private notebookServerInfo: ko.Observable<DataModels.NotebookWorkspaceConnectionInfo>,
|
||||||
|
private onConnectionLost: () => void,
|
||||||
|
private onMemoryUsageInfoUpdate: (update: DataModels.MemoryUsageInfo) => void
|
||||||
|
) {
|
||||||
|
if (notebookServerInfo() && notebookServerInfo().notebookServerEndpoint) {
|
||||||
|
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||||
|
} else {
|
||||||
|
const subscription = notebookServerInfo.subscribe((newServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => {
|
||||||
|
if (newServerInfo && newServerInfo.notebookServerEndpoint) {
|
||||||
|
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||||
|
}
|
||||||
|
subscription.dispose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heartbeat: each ping schedules another ping
|
||||||
|
*/
|
||||||
|
private scheduleHeartbeat(delayMs: number): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getMemoryUsage()
|
||||||
|
.then(memoryUsageInfo => this.onMemoryUsageInfoUpdate(memoryUsageInfo))
|
||||||
|
.finally(() => this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs));
|
||||||
|
}, delayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
||||||
|
if (!this.notebookServerInfo() || !this.notebookServerInfo().notebookServerEndpoint) {
|
||||||
|
const error = "No server endpoint detected";
|
||||||
|
Logger.logError(error, "NotebookContainerClient/getMemoryUsage");
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isResettingWorkspace) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { notebookServerEndpoint, authToken } = this.getNotebookServerConfig();
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${notebookServerEndpoint}/api/metrics/memory`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: authToken,
|
||||||
|
"content-type": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
if (this.reconnectingNotificationId) {
|
||||||
|
NotificationConsoleUtils.clearInProgressMessageWithId(this.reconnectingNotificationId);
|
||||||
|
this.reconnectingNotificationId = "";
|
||||||
|
}
|
||||||
|
const memoryUsageInfo = await response.json();
|
||||||
|
if (memoryUsageInfo) {
|
||||||
|
return {
|
||||||
|
totalKB: memoryUsageInfo.total,
|
||||||
|
freeKB: memoryUsageInfo.free
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
} catch (error) {
|
||||||
|
Logger.logError(error, "NotebookContainerClient/getMemoryUsage");
|
||||||
|
if (!this.reconnectingNotificationId) {
|
||||||
|
this.reconnectingNotificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||||
|
ConsoleDataType.InProgress,
|
||||||
|
"Connection lost with Notebook server. Attempting to reconnect..."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.onConnectionLost();
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async resetWorkspace(): Promise<void> {
|
public async resetWorkspace(): Promise<void> {
|
||||||
this.isResettingWorkspace = true;
|
this.isResettingWorkspace = true;
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ import * as Logger from "../../Common/Logger";
|
|||||||
import { HttpStatusCodes, Areas } from "../../Common/Constants";
|
import { HttpStatusCodes, Areas } from "../../Common/Constants";
|
||||||
import { GitHubReposPane } from "../Panes/GitHubReposPane";
|
import { GitHubReposPane } from "../Panes/GitHubReposPane";
|
||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { IContentProvider } from "@nteract/core";
|
import { IContentProvider } from "@nteract/core";
|
||||||
import { NotebookContentProvider } from "./NotebookComponent/NotebookContentProvider";
|
import { NotebookContentProvider } from "./NotebookComponent/NotebookContentProvider";
|
||||||
import { GitHubContentProvider } from "../../GitHub/GitHubContentProvider";
|
import { GitHubContentProvider } from "../../GitHub/GitHubContentProvider";
|
||||||
import { contents } from "rx-jupyter";
|
import { contents } from "rx-jupyter";
|
||||||
import { NotebookContainerClient } from "./NotebookContainerClient";
|
import { NotebookContainerClient } from "./NotebookContainerClient";
|
||||||
|
import { MemoryUsageInfo } from "../../Contracts/DataModels";
|
||||||
import { NotebookContentClient } from "./NotebookContentClient";
|
import { NotebookContentClient } from "./NotebookContentClient";
|
||||||
import { DialogProps } from "../Controls/DialogReactComponent/DialogComponent";
|
import { DialogProps } from "../Controls/DialogReactComponent/DialogComponent";
|
||||||
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter";
|
||||||
@@ -75,7 +76,11 @@ export default class NotebookManager {
|
|||||||
contents.JupyterContentProvider
|
contents.JupyterContentProvider
|
||||||
);
|
);
|
||||||
|
|
||||||
this.notebookClient = new NotebookContainerClient(this.params.container.notebookServerInfo);
|
this.notebookClient = new NotebookContainerClient(
|
||||||
|
this.params.container.notebookServerInfo,
|
||||||
|
() => this.params.container.initNotebooks(this.params.container.databaseAccount()),
|
||||||
|
(update: MemoryUsageInfo) => this.params.container.memoryUsageInfo(update)
|
||||||
|
);
|
||||||
|
|
||||||
this.notebookContentClient = new NotebookContentClient(
|
this.notebookContentClient = new NotebookContentClient(
|
||||||
this.params.container.notebookServerInfo,
|
this.params.container.notebookServerInfo,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<!-- Add collection header - Start -->
|
<!-- Add collection header - Start -->
|
||||||
<div class="firstdivbg headerline">
|
<div class="firstdivbg headerline">
|
||||||
<span id="containerTitle" data-bind="text: title"></span>
|
<span id="containerTitle" data-bind="text: title"></span>
|
||||||
<div class="closeImg" id="closeBtnAddCollection" role="button" aria-label="Add collection close pane"
|
<div class="closeImg" id="closeBtnAddCollection" role="button" aria-label="Close pane"
|
||||||
data-bind="click: cancel, event: { keypress: onCloseKeyPress }" tabindex="0">
|
data-bind="click: cancel, event: { keypress: onCloseKeyPress }" tabindex="0">
|
||||||
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
<img src="../../../images/close-black.svg" title="Close" alt="Close" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import * as PricingUtils from "../../Utils/PricingUtils";
|
|||||||
import * as SharedConstants from "../../Shared/Constants";
|
import * as SharedConstants from "../../Shared/Constants";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import editable from "../../Common/EditableUtility";
|
import editable from "../../Common/EditableUtility";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { configContext, Platform } from "../../ConfigContext";
|
import { configContext, Platform } from "../../ConfigContext";
|
||||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||||
@@ -943,7 +943,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
const defaultThroughput = this.container.collectionCreationDefaults.throughput;
|
const defaultThroughput = this.container.collectionCreationDefaults.throughput;
|
||||||
this.throughputSinglePartition(defaultThroughput.fixed);
|
this.throughputSinglePartition(defaultThroughput.fixed);
|
||||||
this.throughputMultiPartition(
|
this.throughputMultiPartition(
|
||||||
AddCollectionUtility.getMaxThroughput(this.container.collectionCreationDefaults, this.container)
|
AddCollectionUtility.Utilities.getMaxThroughput(this.container.collectionCreationDefaults, this.container)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.throughputDatabase(defaultThroughput.shared);
|
this.throughputDatabase(defaultThroughput.shared);
|
||||||
@@ -1167,19 +1167,17 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
|
|
||||||
private _updateThroughputLimitByCollectionStorage() {
|
private _updateThroughputLimitByCollectionStorage() {
|
||||||
const storage = this.storage();
|
const storage = this.storage();
|
||||||
const minThroughputRU =
|
const minThroughputRU = AddCollectionUtility.Utilities.getMinRUForStorageOption(
|
||||||
storage === SharedConstants.CollectionCreation.storage10Gb
|
this.container.collectionCreationDefaults,
|
||||||
? SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
storage
|
||||||
: this.container.collectionCreationDefaults.throughput.unlimitedmin;
|
);
|
||||||
|
|
||||||
let maxThroughputRU;
|
let maxThroughputRU = AddCollectionUtility.Utilities.getMaxRUForStorageOption(
|
||||||
|
this.container.collectionCreationDefaults,
|
||||||
|
storage
|
||||||
|
);
|
||||||
if (this.isTryCosmosDBSubscription()) {
|
if (this.isTryCosmosDBSubscription()) {
|
||||||
maxThroughputRU = Constants.TryCosmosExperience.maxRU;
|
maxThroughputRU = Constants.TryCosmosExperience.maxRU;
|
||||||
} else {
|
|
||||||
maxThroughputRU =
|
|
||||||
storage === SharedConstants.CollectionCreation.storage10Gb
|
|
||||||
? SharedConstants.CollectionCreation.DefaultCollectionRUs10K
|
|
||||||
: this.container.collectionCreationDefaults.throughput.unlimitedmax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.minThroughputRU(minThroughputRU);
|
this.minThroughputRU(minThroughputRU);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as AddCollectionUtility from "../../Shared/AddCollectionUtility";
|
||||||
import * as AutoPilotUtils from "../../Utils/AutoPilotUtils";
|
import * as AutoPilotUtils from "../../Utils/AutoPilotUtils";
|
||||||
import * as Constants from "../../Common/Constants";
|
import * as Constants from "../../Common/Constants";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
@@ -7,11 +8,15 @@ import * as PricingUtils from "../../Utils/PricingUtils";
|
|||||||
import * as SharedConstants from "../../Shared/Constants";
|
import * as SharedConstants from "../../Shared/Constants";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import editable from "../../Common/EditableUtility";
|
import editable from "../../Common/EditableUtility";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import EnvironmentUtility from "../../Common/EnvironmentUtility";
|
||||||
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { AddDbUtilities } from "../../Shared/AddDatabaseUtility";
|
||||||
|
import { CassandraAPIDataClient } from "../Tables/TableDataClient";
|
||||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||||
import { createDatabase } from "../../Common/dataAccess/createDatabase";
|
import { createDatabase } from "../../Common/dataAccess/createDatabase";
|
||||||
import { PlatformType } from "../../PlatformType";
|
import { PlatformType } from "../../PlatformType";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export default class AddDatabasePane extends ContextualPaneBase {
|
export default class AddDatabasePane extends ContextualPaneBase {
|
||||||
public defaultExperience: ko.Computed<string>;
|
public defaultExperience: ko.Computed<string>;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Areas } from "../../Common/Constants";
|
|||||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||||
import * as Logger from "../../Common/Logger";
|
import * as Logger from "../../Common/Logger";
|
||||||
import { QueriesGridComponentAdapter } from "../Controls/QueriesGridReactComponent/QueriesGridComponentAdapter";
|
import { QueriesGridComponentAdapter } from "../Controls/QueriesGridReactComponent/QueriesGridComponentAdapter";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import QueryTab from "../Tabs/QueryTab";
|
import QueryTab from "../Tabs/QueryTab";
|
||||||
|
|
||||||
export class BrowseQueriesPane extends ContextualPaneBase {
|
export class BrowseQueriesPane extends ContextualPaneBase {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as ko from "knockout";
|
|||||||
import * as PricingUtils from "../../Utils/PricingUtils";
|
import * as PricingUtils from "../../Utils/PricingUtils";
|
||||||
import * as SharedConstants from "../../Shared/Constants";
|
import * as SharedConstants from "../../Shared/Constants";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { CassandraAPIDataClient } from "../Tables/TableDataClient";
|
import { CassandraAPIDataClient } from "../Tables/TableDataClient";
|
||||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||||
@@ -494,7 +494,9 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||||||
this.selectedSharedAutoPilotTier(null);
|
this.selectedSharedAutoPilotTier(null);
|
||||||
this.selectedAutoPilotThroughput(AutoPilotUtils.minAutoPilotThroughput);
|
this.selectedAutoPilotThroughput(AutoPilotUtils.minAutoPilotThroughput);
|
||||||
this.sharedAutoPilotThroughput(AutoPilotUtils.minAutoPilotThroughput);
|
this.sharedAutoPilotThroughput(AutoPilotUtils.minAutoPilotThroughput);
|
||||||
this.throughput(AddCollectionUtility.getMaxThroughput(this.container.collectionCreationDefaults, this.container));
|
this.throughput(
|
||||||
|
AddCollectionUtility.Utilities.getMaxThroughput(this.container.collectionCreationDefaults, this.container)
|
||||||
|
);
|
||||||
this.keyspaceThroughput(throughputDefaults.shared);
|
this.keyspaceThroughput(throughputDefaults.shared);
|
||||||
this.maxThroughputRU(throughputDefaults.unlimitedmax);
|
this.maxThroughputRU(throughputDefaults.unlimitedmax);
|
||||||
this.minThroughputRU(throughputDefaults.unlimitedmin);
|
this.minThroughputRU(throughputDefaults.unlimitedmin);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as Constants from "../../Common/Constants";
|
|||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { KeyCodes } from "../../Common/Constants";
|
import { KeyCodes } from "../../Common/Constants";
|
||||||
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
|
|
||||||
// TODO: Use specific actions for logging telemetry data
|
// TODO: Use specific actions for logging telemetry data
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||||||
import DeleteCollectionConfirmationPane from "./DeleteCollectionConfirmationPane";
|
import DeleteCollectionConfirmationPane from "./DeleteCollectionConfirmationPane";
|
||||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { TreeNode } from "../../Contracts/ViewModels";
|
import { TreeNode } from "../../Contracts/ViewModels";
|
||||||
import { deleteCollection } from "../../Common/dataAccess/deleteCollection";
|
import { deleteCollection } from "../../Common/dataAccess/deleteCollection";
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ContextualPaneBase } from "./ContextualPaneBase";
|
|||||||
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
|
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
|
||||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { deleteCollection } from "../../Common/dataAccess/deleteCollection";
|
import { deleteCollection } from "../../Common/dataAccess/deleteCollection";
|
||||||
|
|
||||||
export default class DeleteCollectionConfirmationPane extends ContextualPaneBase {
|
export default class DeleteCollectionConfirmationPane extends ContextualPaneBase {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
|||||||
import DeleteDatabaseConfirmationPane from "./DeleteDatabaseConfirmationPane";
|
import DeleteDatabaseConfirmationPane from "./DeleteDatabaseConfirmationPane";
|
||||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { TreeNode } from "../../Contracts/ViewModels";
|
import { TreeNode } from "../../Contracts/ViewModels";
|
||||||
import { TabsManager } from "../Tabs/TabsManager";
|
import { TabsManager } from "../Tabs/TabsManager";
|
||||||
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility"
|
|||||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||||
|
|
||||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
||||||
|
|
||||||
export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
|||||||
import { GitHubClient, IGitHubPageInfo, IGitHubRepo } from "../../GitHub/GitHubClient";
|
import { GitHubClient, IGitHubPageInfo, IGitHubRepo } from "../../GitHub/GitHubClient";
|
||||||
import { IPinnedRepo, JunoClient } from "../../Juno/JunoClient";
|
import { IPinnedRepo, JunoClient } from "../../Juno/JunoClient";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
import { JunoUtils } from "../../Utils/JunoUtils";
|
import { JunoUtils } from "../../Utils/JunoUtils";
|
||||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
|||||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import QueryTab from "../Tabs/QueryTab";
|
import QueryTab from "../Tabs/QueryTab";
|
||||||
|
|
||||||
export class SaveQueryPane extends ContextualPaneBase {
|
export class SaveQueryPane extends ContextualPaneBase {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Areas, KeyCodes } from "../../Common/Constants";
|
|||||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
|
|
||||||
export class SetupNotebooksPane extends ContextualPaneBase {
|
export class SetupNotebooksPane extends ContextualPaneBase {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { DirectoryListProps } from "../Controls/Directory/DirectoryListComponent
|
|||||||
import { DefaultDirectoryDropdownProps } from "../Controls/Directory/DefaultDirectoryDropdownComponent";
|
import { DefaultDirectoryDropdownProps } from "../Controls/Directory/DefaultDirectoryDropdownComponent";
|
||||||
import { DirectoryComponentAdapter } from "../Controls/Directory/DirectoryComponentAdapter";
|
import { DirectoryComponentAdapter } from "../Controls/Directory/DirectoryComponentAdapter";
|
||||||
import SwitchDirectoryPaneTemplate from "./SwitchDirectoryPane.html";
|
import SwitchDirectoryPaneTemplate from "./SwitchDirectoryPane.html";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
|
||||||
class PaneComponent {
|
class PaneComponent {
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as CommonConstants from "../../../Common/Constants";
|
|||||||
import * as Constants from "../Constants";
|
import * as Constants from "../Constants";
|
||||||
import * as Entities from "../Entities";
|
import * as Entities from "../Entities";
|
||||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
|
import { QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
|
||||||
|
|
||||||
// This is the format of the data we will have to pass to Datatable render callback,
|
// This is the format of the data we will have to pass to Datatable render callback,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import * as Utilities from "../Utilities";
|
|||||||
import * as Entities from "../Entities";
|
import * as Entities from "../Entities";
|
||||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||||
import * as TableEntityProcessor from "../TableEntityProcessor";
|
import * as TableEntityProcessor from "../TableEntityProcessor";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as ErrorParserUtility from "../../../Common/ErrorParserUtility";
|
import * as ErrorParserUtility from "../../../Common/ErrorParserUtility";
|
||||||
import * as DataModels from "../../../Contracts/DataModels";
|
import * as DataModels from "../../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import * as HeadersUtility from "../../Common/HeadersUtility";
|
|||||||
import TabsBase from "./TabsBase";
|
import TabsBase from "./TabsBase";
|
||||||
import { DocumentsGridMetrics } from "../../Common/Constants";
|
import { DocumentsGridMetrics } from "../../Common/Constants";
|
||||||
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||||
import DiscardIcon from "../../../images/discard.svg";
|
import DiscardIcon from "../../../images/discard.svg";
|
||||||
import DeleteIcon from "../../../images/delete.svg";
|
import DeleteIcon from "../../../images/delete.svg";
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import editable from "../../Common/EditableUtility";
|
|||||||
import Q from "q";
|
import Q from "q";
|
||||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||||
import TabsBase from "./TabsBase";
|
import TabsBase from "./TabsBase";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { PlatformType } from "../../PlatformType";
|
import { PlatformType } from "../../PlatformType";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import TabsBase from "./TabsBase";
|
|||||||
import { DocumentsGridMetrics } from "../../Common/Constants";
|
import { DocumentsGridMetrics } from "../../Common/Constants";
|
||||||
import { QueryUtils } from "../../Utils/QueryUtils";
|
import { QueryUtils } from "../../Utils/QueryUtils";
|
||||||
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import NewDocumentIcon from "../../../images/NewDocument.svg";
|
import NewDocumentIcon from "../../../images/NewDocument.svg";
|
||||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||||
import DiscardIcon from "../../../images/discard.svg";
|
import DiscardIcon from "../../../images/discard.svg";
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as ErrorParserUtility from "../../Common/ErrorParserUtility";
|
|||||||
import MongoUtility from "../../Common/MongoUtility";
|
import MongoUtility from "../../Common/MongoUtility";
|
||||||
import ObjectId from "../Tree/ObjectId";
|
import ObjectId from "../Tree/ObjectId";
|
||||||
import Q from "q";
|
import Q from "q";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import {
|
import {
|
||||||
createDocument,
|
createDocument,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import EnvironmentUtility from "../../Common/EnvironmentUtility";
|
|||||||
import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation";
|
import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation";
|
||||||
import Q from "q";
|
import Q from "q";
|
||||||
import TabsBase from "./TabsBase";
|
import TabsBase from "./TabsBase";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import { HashMap } from "../../Common/HashMap";
|
import { HashMap } from "../../Common/HashMap";
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import SaveIcon from "../../../images/save-cosmos.svg";
|
|||||||
import ClearAllOutputsIcon from "../../../images/notebook/Notebook-clear-all-outputs.svg";
|
import ClearAllOutputsIcon from "../../../images/notebook/Notebook-clear-all-outputs.svg";
|
||||||
import InterruptKernelIcon from "../../../images/notebook/Notebook-stop.svg";
|
import InterruptKernelIcon from "../../../images/notebook/Notebook-stop.svg";
|
||||||
import KillKernelIcon from "../../../images/notebook/Notebook-stop.svg";
|
import KillKernelIcon from "../../../images/notebook/Notebook-stop.svg";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { Areas, ArmApiVersions } from "../../Common/Constants";
|
import { Areas, ArmApiVersions } from "../../Common/Constants";
|
||||||
import { CommandBarComponentButtonFactory } from "../Menus/CommandBar/CommandBarComponentButtonFactory";
|
import { CommandBarComponentButtonFactory } from "../Menus/CommandBar/CommandBarComponentButtonFactory";
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { HashMap } from "../../Common/HashMap";
|
|||||||
import * as HeadersUtility from "../../Common/HeadersUtility";
|
import * as HeadersUtility from "../../Common/HeadersUtility";
|
||||||
import * as Logger from "../../Common/Logger";
|
import * as Logger from "../../Common/Logger";
|
||||||
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
import { Splitter, SplitterBounds, SplitterDirection } from "../../Common/Splitter";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
|
import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
|
||||||
import { QueryUtils } from "../../Utils/QueryUtils";
|
import { QueryUtils } from "../../Utils/QueryUtils";
|
||||||
import SaveQueryIcon from "../../../images/save-cosmos.svg";
|
import SaveQueryIcon from "../../../images/save-cosmos.svg";
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import editable from "../../Common/EditableUtility";
|
|||||||
import Q from "q";
|
import Q from "q";
|
||||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
import SaveIcon from "../../../images/save-cosmos.svg";
|
||||||
import TabsBase from "./TabsBase";
|
import TabsBase from "./TabsBase";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { PlatformType } from "../../PlatformType";
|
import { PlatformType } from "../../PlatformType";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
|||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import editable from "../../Common/EditableUtility";
|
import editable from "../../Common/EditableUtility";
|
||||||
import ScriptTabBase from "./ScriptTabBase";
|
import ScriptTabBase from "./ScriptTabBase";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
|
import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
|
||||||
import StoredProcedure from "../Tree/StoredProcedure";
|
import StoredProcedure from "../Tree/StoredProcedure";
|
||||||
import { createStoredProcedure, updateStoredProcedure } from "../../Common/DocumentClientUtilityBase";
|
import { createStoredProcedure, updateStoredProcedure } from "../../Common/DocumentClientUtilityBase";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
|||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { RouteHandler } from "../../RouteHandlers/RouteHandler";
|
import { RouteHandler } from "../../RouteHandlers/RouteHandler";
|
||||||
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import ThemeUtility from "../../Common/ThemeUtility";
|
import ThemeUtility from "../../Common/ThemeUtility";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
|||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import ScriptTabBase from "./ScriptTabBase";
|
import ScriptTabBase from "./ScriptTabBase";
|
||||||
import editable from "../../Common/EditableUtility";
|
import editable from "../../Common/EditableUtility";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Trigger from "../Tree/Trigger";
|
import Trigger from "../Tree/Trigger";
|
||||||
import { createTrigger, updateTrigger } from "../../Common/DocumentClientUtilityBase";
|
import { createTrigger, updateTrigger } from "../../Common/DocumentClientUtilityBase";
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as DataModels from "../../Contracts/DataModels";
|
|||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import ScriptTabBase from "./ScriptTabBase";
|
import ScriptTabBase from "./ScriptTabBase";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import UserDefinedFunction from "../Tree/UserDefinedFunction";
|
import UserDefinedFunction from "../Tree/UserDefinedFunction";
|
||||||
import { createUserDefinedFunction, updateUserDefinedFunction } from "../../Common/DocumentClientUtilityBase";
|
import { createUserDefinedFunction, updateUserDefinedFunction } from "../../Common/DocumentClientUtilityBase";
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import * as DataModels from "../../Contracts/DataModels";
|
|||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import { PlatformType } from "../../PlatformType";
|
import { PlatformType } from "../../PlatformType";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
import { OfferUtils } from "../../Utils/OfferUtils";
|
import { OfferUtils } from "../../Utils/OfferUtils";
|
||||||
import { StartUploadMessageParams, UploadDetails, UploadDetailsRecord } from "../../workers/upload/definitions";
|
import { StartUploadMessageParams, UploadDetails, UploadDetailsRecord } from "../../workers/upload/definitions";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as DataModels from "../../Contracts/DataModels";
|
|||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import DatabaseSettingsTab from "../Tabs/DatabaseSettingsTab";
|
import DatabaseSettingsTab from "../Tabs/DatabaseSettingsTab";
|
||||||
import Collection from "./Collection";
|
import Collection from "./Collection";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
|
||||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import * as Logger from "../../Common/Logger";
|
import * as Logger from "../../Common/Logger";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import DocumentId from "./DocumentId";
|
|||||||
import DocumentsTab from "../Tabs/DocumentsTab";
|
import DocumentsTab from "../Tabs/DocumentsTab";
|
||||||
import Q from "q";
|
import Q from "q";
|
||||||
import QueryTab from "../Tabs/QueryTab";
|
import QueryTab from "../Tabs/QueryTab";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
import TabsBase from "../Tabs/TabsBase";
|
||||||
|
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
import Explorer from "../Explorer";
|
|
||||||
import * as ko from "knockout";
|
|
||||||
import { ResourceTreeAdapter } from "./ResourceTreeAdapter";
|
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
|
||||||
|
|
||||||
describe("ResourceTreeAdapter", () => {
|
|
||||||
const mockContainer = (): Explorer =>
|
|
||||||
(({
|
|
||||||
selectedNode: ko.observable<ViewModels.TreeNode>({
|
|
||||||
nodeKind: "nodeKind",
|
|
||||||
rid: "rid",
|
|
||||||
id: ko.observable<string>("id")
|
|
||||||
}),
|
|
||||||
tabsManager: {
|
|
||||||
activeTab: ko.observable<TabsBase>({
|
|
||||||
tabKind: ViewModels.CollectionTabKind.Documents
|
|
||||||
} as TabsBase)
|
|
||||||
},
|
|
||||||
isNotebookEnabled: ko.observable<boolean>(true),
|
|
||||||
nonSystemDatabases: ko.observable<ViewModels.Database[]>([])
|
|
||||||
} as unknown) as Explorer);
|
|
||||||
|
|
||||||
// TODO isDataNodeSelected needs a better design and refactor, but for now, we protect some of the code paths
|
|
||||||
describe("isDataNodeSelected", () => {
|
|
||||||
it("it should not select if no selected node", () => {
|
|
||||||
const explorer = mockContainer();
|
|
||||||
explorer.selectedNode(undefined);
|
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("foo", "bar", undefined);
|
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("it should not select incorrect subnodekinds", () => {
|
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(mockContainer());
|
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("foo", "bar", undefined);
|
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("it should not select if no active tab", () => {
|
|
||||||
const explorer = mockContainer();
|
|
||||||
explorer.tabsManager.activeTab(undefined);
|
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("foo", "bar", undefined);
|
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should select if correct database node regardless of subnodekinds", () => {
|
|
||||||
const subNodeKind = ViewModels.CollectionTabKind.Documents;
|
|
||||||
const explorer = mockContainer();
|
|
||||||
explorer.selectedNode(({
|
|
||||||
nodeKind: "Database",
|
|
||||||
rid: "dbrid",
|
|
||||||
id: ko.observable<string>("id"),
|
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind)
|
|
||||||
} as unknown) as ViewModels.TreeNode);
|
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("dbrid", "Database", [
|
|
||||||
ViewModels.CollectionTabKind.Documents
|
|
||||||
]);
|
|
||||||
expect(isDataNodeSelected).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should select correct collection node (documents or graph node)", () => {
|
|
||||||
let subNodeKind = ViewModels.CollectionTabKind.Documents;
|
|
||||||
const explorer = mockContainer();
|
|
||||||
explorer.tabsManager.activeTab({
|
|
||||||
tabKind: subNodeKind
|
|
||||||
} as TabsBase);
|
|
||||||
explorer.selectedNode(({
|
|
||||||
nodeKind: "Collection",
|
|
||||||
rid: "collrid",
|
|
||||||
id: ko.observable<string>("id"),
|
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind)
|
|
||||||
} as unknown) as ViewModels.TreeNode);
|
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
|
||||||
let isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("collrid", "Collection", [subNodeKind]);
|
|
||||||
expect(isDataNodeSelected).toBeTruthy();
|
|
||||||
|
|
||||||
subNodeKind = ViewModels.CollectionTabKind.Graph;
|
|
||||||
explorer.tabsManager.activeTab({
|
|
||||||
tabKind: subNodeKind
|
|
||||||
} as TabsBase);
|
|
||||||
explorer.selectedNode(({
|
|
||||||
nodeKind: "Collection",
|
|
||||||
rid: "collrid",
|
|
||||||
id: ko.observable<string>("id"),
|
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind)
|
|
||||||
} as unknown) as ViewModels.TreeNode);
|
|
||||||
isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("collrid", "Collection", [subNodeKind]);
|
|
||||||
expect(isDataNodeSelected).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not select incorrect collection node (e.g. Settings)", () => {
|
|
||||||
const explorer = mockContainer();
|
|
||||||
explorer.selectedNode(({
|
|
||||||
nodeKind: "Collection",
|
|
||||||
rid: "collrid",
|
|
||||||
id: ko.observable<string>("id"),
|
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(ViewModels.CollectionTabKind.Documents)
|
|
||||||
} as unknown) as ViewModels.TreeNode);
|
|
||||||
explorer.tabsManager.activeTab({
|
|
||||||
tabKind: ViewModels.CollectionTabKind.Documents
|
|
||||||
} as TabsBase);
|
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("collrid", "Collection", [
|
|
||||||
ViewModels.CollectionTabKind.Settings
|
|
||||||
]);
|
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -19,7 +19,7 @@ import { ArrayHashMap } from "../../Common/ArrayHashMap";
|
|||||||
import { NotebookUtil } from "../Notebook/NotebookUtil";
|
import { NotebookUtil } from "../Notebook/NotebookUtil";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
import { IPinnedRepo } from "../../Juno/JunoClient";
|
import { IPinnedRepo } from "../../Juno/JunoClient";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { Areas } from "../../Common/Constants";
|
import { Areas } from "../../Common/Constants";
|
||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
@@ -191,7 +191,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
databaseNode.children.push({
|
databaseNode.children.push({
|
||||||
label: "Scale",
|
label: "Scale",
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(database.rid, "Database", [ViewModels.CollectionTabKind.DatabaseSettings]),
|
this.isDataNodeSelected(database.rid, "Database", ViewModels.CollectionTabKind.DatabaseSettings),
|
||||||
onClick: database.onSettingsClick.bind(database)
|
onClick: database.onSettingsClick.bind(database)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -235,18 +235,14 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
data: collection.rid
|
data: collection.rid
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
isSelected: () =>
|
isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", ViewModels.CollectionTabKind.Documents),
|
||||||
this.isDataNodeSelected(collection.rid, "Collection", [
|
|
||||||
ViewModels.CollectionTabKind.Documents,
|
|
||||||
ViewModels.CollectionTabKind.Graph
|
|
||||||
]),
|
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(this.container, collection)
|
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(this.container, collection)
|
||||||
});
|
});
|
||||||
|
|
||||||
children.push({
|
children.push({
|
||||||
label: database.isDatabaseShared() || this.container.isServerlessEnabled() ? "Settings" : "Scale & Settings",
|
label: database.isDatabaseShared() || this.container.isServerlessEnabled() ? "Settings" : "Scale & Settings",
|
||||||
onClick: collection.onSettingsClick.bind(collection),
|
onClick: collection.onSettingsClick.bind(collection),
|
||||||
isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", [ViewModels.CollectionTabKind.Settings])
|
isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", ViewModels.CollectionTabKind.Settings)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ResourceTreeAdapter.showScriptNodes(this.container)) {
|
if (ResourceTreeAdapter.showScriptNodes(this.container)) {
|
||||||
@@ -268,8 +264,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
children.push({
|
children.push({
|
||||||
label: "Conflicts",
|
label: "Conflicts",
|
||||||
onClick: collection.onConflictsClick.bind(collection),
|
onClick: collection.onConflictsClick.bind(collection),
|
||||||
isSelected: () =>
|
isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", ViewModels.CollectionTabKind.Conflicts)
|
||||||
this.isDataNodeSelected(collection.rid, "Collection", [ViewModels.CollectionTabKind.Conflicts])
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +302,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
label: sp.id(),
|
label: sp.id(),
|
||||||
onClick: sp.open.bind(sp),
|
onClick: sp.open.bind(sp),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.rid, "Collection", [ViewModels.CollectionTabKind.StoredProcedures]),
|
this.isDataNodeSelected(collection.rid, "Collection", ViewModels.CollectionTabKind.StoredProcedures),
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createStoreProcedureContextMenuItems(this.container, sp)
|
contextMenu: ResourceTreeContextMenuButtonFactory.createStoreProcedureContextMenuItems(this.container, sp)
|
||||||
})),
|
})),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@@ -326,7 +321,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
label: udf.id(),
|
label: udf.id(),
|
||||||
onClick: udf.open.bind(udf),
|
onClick: udf.open.bind(udf),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.rid, "Collection", [ViewModels.CollectionTabKind.UserDefinedFunctions]),
|
this.isDataNodeSelected(collection.rid, "Collection", ViewModels.CollectionTabKind.UserDefinedFunctions),
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createUserDefinedFunctionContextMenuItems(this.container, udf)
|
contextMenu: ResourceTreeContextMenuButtonFactory.createUserDefinedFunctionContextMenuItems(this.container, udf)
|
||||||
})),
|
})),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@@ -344,8 +339,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
children: collection.triggers().map((trigger: Trigger) => ({
|
children: collection.triggers().map((trigger: Trigger) => ({
|
||||||
label: trigger.id(),
|
label: trigger.id(),
|
||||||
onClick: trigger.open.bind(trigger),
|
onClick: trigger.open.bind(trigger),
|
||||||
isSelected: () =>
|
isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", ViewModels.CollectionTabKind.Triggers),
|
||||||
this.isDataNodeSelected(collection.rid, "Collection", [ViewModels.CollectionTabKind.Triggers]),
|
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createTriggerContextMenuItems(this.container, trigger)
|
contextMenu: ResourceTreeContextMenuButtonFactory.createTriggerContextMenuItems(this.container, trigger)
|
||||||
})),
|
})),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@@ -703,19 +697,13 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private isDataNodeSelected(rid: string, nodeKind: string, subnodeKind: ViewModels.CollectionTabKind): boolean {
|
||||||
* public for testing purposes
|
|
||||||
* @param rid
|
|
||||||
* @param nodeKind
|
|
||||||
* @param subnodeKinds
|
|
||||||
*/
|
|
||||||
public isDataNodeSelected(rid: string, nodeKind: string, subnodeKinds: ViewModels.CollectionTabKind[]): boolean {
|
|
||||||
if (!this.container.selectedNode || !this.container.selectedNode()) {
|
if (!this.container.selectedNode || !this.container.selectedNode()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const selectedNode = this.container.selectedNode();
|
const selectedNode = this.container.selectedNode();
|
||||||
|
|
||||||
if (subnodeKinds === undefined || !Array.isArray(subnodeKinds)) {
|
if (subnodeKind === undefined) {
|
||||||
return selectedNode.rid === rid && selectedNode.nodeKind === nodeKind;
|
return selectedNode.rid === rid && selectedNode.nodeKind === nodeKind;
|
||||||
} else {
|
} else {
|
||||||
const activeTab = this.container.tabsManager.activeTab();
|
const activeTab = this.container.tabsManager.activeTab();
|
||||||
@@ -728,10 +716,10 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
activeTab &&
|
activeTab &&
|
||||||
subnodeKinds.includes(activeTab.tabKind) &&
|
activeTab.tabKind === subnodeKind &&
|
||||||
selectedNode.rid === rid &&
|
selectedNode.rid === rid &&
|
||||||
selectedSubnodeKind !== undefined &&
|
selectedSubnodeKind !== undefined &&
|
||||||
subnodeKinds.includes(selectedSubnodeKind)
|
selectedSubnodeKind === subnodeKind
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as DataModels from "../../Contracts/DataModels";
|
|||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
|
||||||
import StoredProcedureTab from "../Tabs/StoredProcedureTab";
|
import StoredProcedureTab from "../Tabs/StoredProcedureTab";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { deleteStoredProcedure, executeStoredProcedure } from "../../Common/DocumentClientUtilityBase";
|
import { deleteStoredProcedure, executeStoredProcedure } from "../../Common/DocumentClientUtilityBase";
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
import TabsBase from "../Tabs/TabsBase";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as Constants from "../../Common/Constants";
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import TriggerTab from "../Tabs/TriggerTab";
|
import TriggerTab from "../Tabs/TriggerTab";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { deleteTrigger } from "../../Common/DocumentClientUtilityBase";
|
import { deleteTrigger } from "../../Common/DocumentClientUtilityBase";
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as Constants from "../../Common/Constants";
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import UserDefinedFunctionTab from "../Tabs/UserDefinedFunctionTab";
|
import UserDefinedFunctionTab from "../Tabs/UserDefinedFunctionTab";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { deleteUserDefinedFunction } from "../../Common/DocumentClientUtilityBase";
|
import { deleteUserDefinedFunction } from "../../Common/DocumentClientUtilityBase";
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { MeControlComponentAdapter } from "./Explorer/Menus/NavBar/MeControlComp
|
|||||||
import { MessageTypes } from "./Contracts/ExplorerContracts";
|
import { MessageTypes } from "./Contracts/ExplorerContracts";
|
||||||
import * as ReactBindingHandler from "./Bindings/ReactBindingHandler";
|
import * as ReactBindingHandler from "./Bindings/ReactBindingHandler";
|
||||||
import { SwitchDirectoryPane, SwitchDirectoryPaneComponent } from "./Explorer/Panes/SwitchDirectoryPane";
|
import { SwitchDirectoryPane, SwitchDirectoryPaneComponent } from "./Explorer/Panes/SwitchDirectoryPane";
|
||||||
import * as TelemetryProcessor from "./Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "./Shared/Telemetry/TelemetryProcessor";
|
||||||
import { isInvalidParentFrameOrigin } from "./Utils/MessageValidation";
|
import { isInvalidParentFrameOrigin } from "./Utils/MessageValidation";
|
||||||
import "../less/hostedexplorer.less";
|
import "../less/hostedexplorer.less";
|
||||||
import "./Explorer/Menus/NavBar/MeControlComponent.less";
|
import "./Explorer/Menus/NavBar/MeControlComponent.less";
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ import "url-polyfill/url-polyfill.min";
|
|||||||
// import "./ReactDevTools"
|
// import "./ReactDevTools"
|
||||||
|
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import * as TelemetryProcessor from "./Shared/Telemetry/TelemetryProcessor";
|
import TelemetryProcessor from "./Shared/Telemetry/TelemetryProcessor";
|
||||||
import * as ViewModels from "./Contracts/ViewModels";
|
import * as ViewModels from "./Contracts/ViewModels";
|
||||||
import { Action, ActionModifiers } from "./Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "./Shared/Telemetry/TelemetryConstants";
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +1,162 @@
|
|||||||
import * as ko from "knockout";
|
import * as SharedConstants from "../Shared/Constants";
|
||||||
import { Collection, Database } from "../Contracts/ViewModels";
|
import { AddDbUtilities } from "../Shared/AddDatabaseUtility";
|
||||||
import { getMaxThroughput } from "./AddCollectionUtility";
|
import { CreateCollectionUtilities, CreateSqlCollectionUtilities, Utilities } from "./AddCollectionUtility";
|
||||||
import Explorer from "../Explorer/Explorer";
|
jest.mock("AddDatabaseUtility");
|
||||||
|
|
||||||
describe("getMaxThroughput", () => {
|
const armEndpoint = "https://management.azure.com";
|
||||||
it("default unlimited throughput setting", () => {
|
|
||||||
const defaults = {
|
|
||||||
storage: "100",
|
|
||||||
throughput: {
|
|
||||||
fixed: 400,
|
|
||||||
unlimited: 400,
|
|
||||||
unlimitedmax: 1000000,
|
|
||||||
unlimitedmin: 400,
|
|
||||||
shared: 400
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(getMaxThroughput(defaults, {} as Explorer)).toEqual(defaults.throughput.unlimited);
|
describe("Add Collection Utitlity", () => {
|
||||||
});
|
describe("createSqlCollection", () => {
|
||||||
|
it("should invoke createSqlCollectionWithARM if create database is false", () => {
|
||||||
describe("no unlimited throughput setting", () => {
|
const properties = {
|
||||||
const defaults = {
|
uniqueKeyPolicy: { uniqueKeys: [{ paths: [""] }] },
|
||||||
storage: "100",
|
cd: false,
|
||||||
throughput: {
|
coll: "abc-collection",
|
||||||
fixed: 400,
|
db: "a1-db",
|
||||||
unlimited: {
|
dba: "main",
|
||||||
collectionThreshold: 3,
|
offerThroughput: 50000,
|
||||||
lessThanOrEqualToThreshold: 400,
|
pk: "state",
|
||||||
greatThanThreshold: 500
|
sid: "a1",
|
||||||
},
|
rg: "b1",
|
||||||
unlimitedmax: 1000000,
|
st: true,
|
||||||
unlimitedmin: 400,
|
defaultTtl: -1,
|
||||||
shared: 400
|
indexingPolicy: SharedConstants.IndexingPolicies.AllPropertiesIndexed,
|
||||||
}
|
partitionKeyVersion: 2
|
||||||
};
|
};
|
||||||
|
const additionalOptions = {};
|
||||||
const mockCollection1 = { id: ko.observable("collection1") } as Collection;
|
const createSqlCollectionWithARMSpy = jest.spyOn(CreateSqlCollectionUtilities, "createSqlCollectionWithARM");
|
||||||
const mockCollection2 = { id: ko.observable("collection2") } as Collection;
|
CreateSqlCollectionUtilities.createSqlCollection(
|
||||||
const mockCollection3 = { id: ko.observable("collection3") } as Collection;
|
armEndpoint,
|
||||||
const mockCollection4 = { id: ko.observable("collection4") } as Collection;
|
properties.db,
|
||||||
const mockDatabase = {} as Database;
|
properties.defaultTtl,
|
||||||
const mockContainer = {
|
properties.coll,
|
||||||
databases: ko.observableArray([mockDatabase])
|
properties.indexingPolicy,
|
||||||
} as Explorer;
|
properties.offerThroughput,
|
||||||
|
properties.pk,
|
||||||
it("less than or equal to collection threshold", () => {
|
properties.partitionKeyVersion,
|
||||||
mockDatabase.collections = ko.observableArray([mockCollection1, mockCollection2]);
|
properties.cd,
|
||||||
expect(getMaxThroughput(defaults, mockContainer)).toEqual(
|
properties.st,
|
||||||
defaults.throughput.unlimited.lessThanOrEqualToThreshold
|
properties.sid,
|
||||||
|
properties.rg,
|
||||||
|
properties.dba,
|
||||||
|
properties.uniqueKeyPolicy,
|
||||||
|
additionalOptions
|
||||||
);
|
);
|
||||||
|
expect(createSqlCollectionWithARMSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("exceeds collection threshold", () => {
|
it("should invoke createSqlDatabase + createSqlCollectionWithARM if create database is true", () => {
|
||||||
mockDatabase.collections = ko.observableArray([
|
const properties = {
|
||||||
mockCollection1,
|
uniqueKeyPolicy: { uniqueKeys: [{ paths: [""] }] },
|
||||||
mockCollection2,
|
cd: true,
|
||||||
mockCollection3,
|
coll: "abc-collection",
|
||||||
mockCollection4
|
db: "a1-db",
|
||||||
]);
|
dba: "main",
|
||||||
expect(getMaxThroughput(defaults, mockContainer)).toEqual(defaults.throughput.unlimited.greatThanThreshold);
|
offerThroughput: 50000,
|
||||||
|
pk: "state",
|
||||||
|
sid: "a1",
|
||||||
|
rg: "b1",
|
||||||
|
st: true,
|
||||||
|
analyticalStorageTtl: -1,
|
||||||
|
indexingPolicy: SharedConstants.IndexingPolicies.AllPropertiesIndexed,
|
||||||
|
partitionKeyVersion: 2
|
||||||
|
};
|
||||||
|
const additionalOptions = {};
|
||||||
|
const createSqlCollectionWithARMSpy = jest.spyOn(CreateSqlCollectionUtilities, "createSqlCollectionWithARM");
|
||||||
|
const createSqlDatabaseSpy = jest.spyOn(AddDbUtilities, "createSqlDatabase");
|
||||||
|
CreateSqlCollectionUtilities.createSqlCollection(
|
||||||
|
armEndpoint,
|
||||||
|
properties.db,
|
||||||
|
properties.analyticalStorageTtl,
|
||||||
|
properties.coll,
|
||||||
|
properties.indexingPolicy,
|
||||||
|
properties.offerThroughput,
|
||||||
|
properties.pk,
|
||||||
|
properties.partitionKeyVersion,
|
||||||
|
properties.cd,
|
||||||
|
properties.st,
|
||||||
|
properties.sid,
|
||||||
|
properties.rg,
|
||||||
|
properties.dba,
|
||||||
|
properties.uniqueKeyPolicy,
|
||||||
|
additionalOptions
|
||||||
|
);
|
||||||
|
expect(createSqlCollectionWithARMSpy).toHaveBeenCalled();
|
||||||
|
expect(createSqlDatabaseSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Add Collection Utitlity", () => {
|
||||||
|
describe("createGremlinGraph", () => {
|
||||||
|
it("should invoke createGremlinGraphWithARM if create database is false", () => {
|
||||||
|
const properties = {
|
||||||
|
cd: false,
|
||||||
|
coll: "abc-collection",
|
||||||
|
db: "a1-db",
|
||||||
|
dba: "main",
|
||||||
|
offerThroughput: 50000,
|
||||||
|
pk: "state",
|
||||||
|
sid: "a1",
|
||||||
|
rg: "b1",
|
||||||
|
st: true,
|
||||||
|
indexingPolicy: SharedConstants.IndexingPolicies.AllPropertiesIndexed,
|
||||||
|
partitionKeyVersion: 2
|
||||||
|
};
|
||||||
|
const additionalOptions = {};
|
||||||
|
const createGremlinGraphWithARMSpy = jest.spyOn(CreateCollectionUtilities, "createGremlinGraphWithARM");
|
||||||
|
CreateCollectionUtilities.createGremlinGraph(
|
||||||
|
armEndpoint,
|
||||||
|
properties.db,
|
||||||
|
properties.coll,
|
||||||
|
properties.indexingPolicy,
|
||||||
|
properties.offerThroughput,
|
||||||
|
properties.pk,
|
||||||
|
properties.partitionKeyVersion,
|
||||||
|
properties.cd,
|
||||||
|
properties.st,
|
||||||
|
properties.sid,
|
||||||
|
properties.rg,
|
||||||
|
properties.dba,
|
||||||
|
additionalOptions
|
||||||
|
);
|
||||||
|
expect(createGremlinGraphWithARMSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke createGremlinDatabase + createGremlinGraphWithARM if create database is true", () => {
|
||||||
|
const properties = {
|
||||||
|
cd: true,
|
||||||
|
coll: "abc-collection",
|
||||||
|
db: "a1-db",
|
||||||
|
dba: "main",
|
||||||
|
offerThroughput: 50000,
|
||||||
|
pk: "state",
|
||||||
|
sid: "a1",
|
||||||
|
rg: "b1",
|
||||||
|
st: true,
|
||||||
|
indexingPolicy: SharedConstants.IndexingPolicies.AllPropertiesIndexed,
|
||||||
|
partitionKeyVersion: 2
|
||||||
|
};
|
||||||
|
const additionalOptions = {};
|
||||||
|
const createGremlinGraphWithARMSpy = jest.spyOn(CreateCollectionUtilities, "createGremlinGraphWithARM");
|
||||||
|
const createGremlinDatabaseSpy = jest.spyOn(AddDbUtilities, "createGremlinDatabase");
|
||||||
|
CreateCollectionUtilities.createGremlinGraph(
|
||||||
|
armEndpoint,
|
||||||
|
properties.db,
|
||||||
|
properties.coll,
|
||||||
|
properties.indexingPolicy,
|
||||||
|
properties.offerThroughput,
|
||||||
|
properties.pk,
|
||||||
|
properties.partitionKeyVersion,
|
||||||
|
properties.cd,
|
||||||
|
properties.st,
|
||||||
|
properties.sid,
|
||||||
|
properties.rg,
|
||||||
|
properties.dba,
|
||||||
|
additionalOptions
|
||||||
|
);
|
||||||
|
expect(createGremlinDatabaseSpy).toHaveBeenCalled();
|
||||||
|
expect(createGremlinGraphWithARMSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,23 +1,303 @@
|
|||||||
import { any } from "underscore";
|
import * as _ from "underscore";
|
||||||
import { CollectionCreationDefaults } from "../Contracts/ViewModels";
|
import * as DataExplorerConstants from "../Common/Constants";
|
||||||
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
|
import * as SharedConstants from "./Constants";
|
||||||
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
|
import { AddDbUtilities } from "../Shared/AddDatabaseUtility";
|
||||||
|
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
|
import { HttpStatusCodes } from "../Common/Constants";
|
||||||
|
import { sendMessage } from "../Common/MessageHandler";
|
||||||
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
|
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
|
|
||||||
export const getMaxThroughput = (defaults: CollectionCreationDefaults, container: Explorer): number => {
|
export class CreateSqlCollectionUtilities {
|
||||||
const throughput = defaults.throughput.unlimited;
|
public static createSqlCollection(
|
||||||
if (typeof throughput === "number") {
|
armEndpoint: string,
|
||||||
return throughput;
|
databaseId: string,
|
||||||
} else {
|
analyticalStorageTtl: number,
|
||||||
return _exceedsThreshold(throughput.collectionThreshold, container)
|
collectionId: string,
|
||||||
? throughput.greatThanThreshold
|
indexingPolicy: DataModels.IndexingPolicy,
|
||||||
: throughput.lessThanOrEqualToThreshold;
|
offerThroughput: number,
|
||||||
|
partitionKey: string,
|
||||||
|
partitionKeyVersion: number,
|
||||||
|
createDatabase: boolean,
|
||||||
|
useDatabaseSharedOffer: boolean,
|
||||||
|
sid: string,
|
||||||
|
rg: string,
|
||||||
|
dba: string,
|
||||||
|
uniqueKeyPolicy: DataModels.UniqueKeyPolicy,
|
||||||
|
additionalOptions: DataModels.RpOptions
|
||||||
|
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||||
|
const params: DataModels.SqlCollectionParameters = {
|
||||||
|
uniqueKeyPolicy,
|
||||||
|
db: databaseId,
|
||||||
|
coll: collectionId,
|
||||||
|
pk: partitionKey,
|
||||||
|
offerThroughput,
|
||||||
|
cd: createDatabase,
|
||||||
|
st: useDatabaseSharedOffer,
|
||||||
|
sid,
|
||||||
|
rg,
|
||||||
|
dba,
|
||||||
|
analyticalStorageTtl,
|
||||||
|
indexingPolicy,
|
||||||
|
partitionKeyVersion
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.cd) {
|
||||||
|
return AddDbUtilities.createSqlDatabase(armEndpoint, params, additionalOptions).then(() => {
|
||||||
|
return CreateSqlCollectionUtilities.createSqlCollectionWithARM(armEndpoint, params, additionalOptions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return CreateSqlCollectionUtilities.createSqlCollectionWithARM(armEndpoint, params, additionalOptions);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const _exceedsThreshold = (unlimitedThreshold: number, container: Explorer): boolean => {
|
public static async createSqlCollectionWithARM(
|
||||||
const databases = (container && container.databases && container.databases()) || [];
|
armEndpoint: string,
|
||||||
return any(
|
params: DataModels.SqlCollectionParameters,
|
||||||
databases,
|
rpOptions: DataModels.RpOptions
|
||||||
database =>
|
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||||
database && database.collections && database.collections() && database.collections().length > unlimitedThreshold
|
const rpPayloadToCreateCollection: DataModels.SqlCollectionCreationRequest = {
|
||||||
);
|
properties: {
|
||||||
};
|
resource: {
|
||||||
|
id: params.coll,
|
||||||
|
partitionKey: {
|
||||||
|
paths: [params.pk],
|
||||||
|
kind: "Hash",
|
||||||
|
version: params.partitionKeyVersion
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.analyticalStorageTtl) {
|
||||||
|
rpPayloadToCreateCollection.properties.resource.analyticalStorageTtl = params.analyticalStorageTtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.indexingPolicy) {
|
||||||
|
rpPayloadToCreateCollection.properties.resource.indexingPolicy = params.indexingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.st) {
|
||||||
|
if (rpOptions) {
|
||||||
|
rpPayloadToCreateCollection.properties.options = rpOptions;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateCollection.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.uniqueKeyPolicy) {
|
||||||
|
rpPayloadToCreateCollection.properties.resource.uniqueKeyPolicy = params.uniqueKeyPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response = await new ResourceProviderClient<DataModels.CreateCollectionWithRpResponse>(armEndpoint).putAsync(
|
||||||
|
CreateSqlCollectionUtilities.getSqlCollectionUri(params),
|
||||||
|
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||||
|
rpPayloadToCreateCollection
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
} catch (response) {
|
||||||
|
NotificationConsoleUtils.logConsoleMessage(
|
||||||
|
ConsoleDataType.Error,
|
||||||
|
`Error creating collection: ${JSON.stringify(response)}`
|
||||||
|
);
|
||||||
|
if (response.status === HttpStatusCodes.Forbidden) {
|
||||||
|
sendMessage({ type: MessageTypes.ForbiddenError });
|
||||||
|
}
|
||||||
|
throw new Error(`Error creating collection`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getSqlCollectionUri(params: DataModels.SqlCollectionParameters): string {
|
||||||
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${params.dba}/sqlDatabases/${params.db}/containers/${params.coll}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateCollectionUtilities {
|
||||||
|
public static createGremlinGraph(
|
||||||
|
armEndpoint: string,
|
||||||
|
databaseId: string,
|
||||||
|
collectionId: string,
|
||||||
|
indexingPolicy: DataModels.IndexingPolicy,
|
||||||
|
offerThroughput: number,
|
||||||
|
partitionKey: string,
|
||||||
|
partitionKeyVersion: number,
|
||||||
|
createDatabase: boolean,
|
||||||
|
useDatabaseSharedOffer: boolean,
|
||||||
|
sid: string,
|
||||||
|
rg: string,
|
||||||
|
dba: string,
|
||||||
|
additionalOptions: DataModels.RpOptions
|
||||||
|
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||||
|
const params: DataModels.GraphParameters = {
|
||||||
|
db: databaseId,
|
||||||
|
coll: collectionId,
|
||||||
|
pk: partitionKey,
|
||||||
|
offerThroughput,
|
||||||
|
cd: createDatabase,
|
||||||
|
st: useDatabaseSharedOffer,
|
||||||
|
sid,
|
||||||
|
rg,
|
||||||
|
dba,
|
||||||
|
indexingPolicy,
|
||||||
|
partitionKeyVersion
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.cd) {
|
||||||
|
return AddDbUtilities.createGremlinDatabase(armEndpoint, params, additionalOptions).then(() => {
|
||||||
|
return CreateCollectionUtilities.createGremlinGraphWithARM(armEndpoint, params, additionalOptions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return CreateCollectionUtilities.createGremlinGraphWithARM(armEndpoint, params, additionalOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async createGremlinGraphWithARM(
|
||||||
|
armEndpoint: string,
|
||||||
|
params: DataModels.GraphParameters,
|
||||||
|
rpOptions: DataModels.RpOptions
|
||||||
|
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||||
|
const rpPayloadToCreateCollection: DataModels.GraphCreationRequest = {
|
||||||
|
properties: {
|
||||||
|
resource: {
|
||||||
|
id: params.coll,
|
||||||
|
partitionKey: {
|
||||||
|
paths: [params.pk],
|
||||||
|
kind: "Hash",
|
||||||
|
version: params.partitionKeyVersion
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.indexingPolicy) {
|
||||||
|
rpPayloadToCreateCollection.properties.resource.indexingPolicy = params.indexingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.st) {
|
||||||
|
if (rpOptions) {
|
||||||
|
rpPayloadToCreateCollection.properties.options = rpOptions;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateCollection.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response = await new ResourceProviderClient<DataModels.CreateCollectionWithRpResponse>(armEndpoint).putAsync(
|
||||||
|
CreateCollectionUtilities.getGremlinGraphUri(params),
|
||||||
|
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||||
|
rpPayloadToCreateCollection
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
} catch (response) {
|
||||||
|
NotificationConsoleUtils.logConsoleMessage(
|
||||||
|
ConsoleDataType.Error,
|
||||||
|
`Error creating graph: ${JSON.stringify(response)}`
|
||||||
|
);
|
||||||
|
if (response.status === HttpStatusCodes.Forbidden) {
|
||||||
|
sendMessage({ type: MessageTypes.ForbiddenError });
|
||||||
|
}
|
||||||
|
throw new Error(`Error creating graph`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getGremlinGraphUri(params: DataModels.GraphParameters): string {
|
||||||
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${params.dba}/gremlinDatabases/${params.db}/graphs/${params.coll}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class Utilities {
|
||||||
|
public static async createAzureTableWithARM(
|
||||||
|
armEndpoint: string,
|
||||||
|
params: DataModels.CreateDatabaseAndCollectionRequest,
|
||||||
|
rpOptions: DataModels.RpOptions
|
||||||
|
): Promise<any> {
|
||||||
|
const rpPayloadToCreateDatabase: DataModels.CreationRequest = {
|
||||||
|
properties: {
|
||||||
|
resource: {
|
||||||
|
id: params.collectionId
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!params.databaseLevelThroughput) {
|
||||||
|
if (rpOptions) {
|
||||||
|
rpPayloadToCreateDatabase.properties.options = rpOptions;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateDatabase.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await new ResourceProviderClient(armEndpoint).putAsync(
|
||||||
|
Utilities._getAzureTableUri(params),
|
||||||
|
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||||
|
rpPayloadToCreateDatabase
|
||||||
|
);
|
||||||
|
} catch (reason) {
|
||||||
|
NotificationConsoleUtils.logConsoleMessage(
|
||||||
|
ConsoleDataType.Error,
|
||||||
|
`Error creating table: ${JSON.stringify(reason)}, Payload: ${params}`
|
||||||
|
);
|
||||||
|
if (reason.status === HttpStatusCodes.Forbidden) {
|
||||||
|
sendMessage({ type: MessageTypes.ForbiddenError });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error(`Error creating table`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getMaxRUForStorageOption(
|
||||||
|
defaults: ViewModels.CollectionCreationDefaults,
|
||||||
|
storageOption: string
|
||||||
|
): number {
|
||||||
|
if (storageOption === SharedConstants.CollectionCreation.storage10Gb) {
|
||||||
|
return SharedConstants.CollectionCreation.DefaultCollectionRUs10K;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults.throughput.unlimitedmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getMinRUForStorageOption(
|
||||||
|
defaults: ViewModels.CollectionCreationDefaults,
|
||||||
|
storageOption: string
|
||||||
|
): number {
|
||||||
|
if (storageOption === SharedConstants.CollectionCreation.storage10Gb) {
|
||||||
|
return SharedConstants.CollectionCreation.DefaultCollectionRUs400;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults.throughput.unlimitedmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getMaxThroughput(defaults: ViewModels.CollectionCreationDefaults, container: Explorer): number {
|
||||||
|
const throughput = defaults.throughput.unlimited;
|
||||||
|
if (typeof throughput === "number") {
|
||||||
|
return throughput;
|
||||||
|
} else {
|
||||||
|
return this._exceedsThreshold(throughput.collectionThreshold, container)
|
||||||
|
? throughput.greatThanThreshold
|
||||||
|
: throughput.lessThanOrEqualToThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _exceedsThreshold(unlimitedThreshold: number, container: Explorer): boolean {
|
||||||
|
const databases = (container && container.databases && container.databases()) || [];
|
||||||
|
return _.any(
|
||||||
|
databases,
|
||||||
|
database =>
|
||||||
|
database && database.collections && database.collections() && database.collections().length > unlimitedThreshold
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _getAzureTableUri(params: DataModels.CreateDatabaseAndCollectionRequest): string {
|
||||||
|
return `subscriptions/${userContext.subscriptionId}/resourceGroups/${userContext.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/tables/${params.collectionId}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
153
src/Shared/AddDatabaseUtility.test.ts
Normal file
153
src/Shared/AddDatabaseUtility.test.ts
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import { AddDbUtilities } from "./AddDatabaseUtility";
|
||||||
|
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||||
|
jest.mock("../ResourceProvider/ResourceProviderClient.ts");
|
||||||
|
|
||||||
|
describe("Add Database Utitlity", () => {
|
||||||
|
const armEndpoint = "https://management.azure.com";
|
||||||
|
const properties = {
|
||||||
|
pk: "state",
|
||||||
|
coll: "abc-collection",
|
||||||
|
cd: true,
|
||||||
|
db: "a1-db",
|
||||||
|
offerThroughput: 50000,
|
||||||
|
st: true,
|
||||||
|
sid: "a1",
|
||||||
|
rg: "b1",
|
||||||
|
dba: "main"
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("getRpClient", () => {
|
||||||
|
it("should return an instance of ResourceProviderClient", () => {
|
||||||
|
expect(AddDbUtilities.getRpClient()).not.toBeFalsy();
|
||||||
|
expect(AddDbUtilities.getRpClient()).toBeInstanceOf(ResourceProviderClient);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getGremlinDatabaseUri", () => {
|
||||||
|
it("should return a uri in the correct format", () => {
|
||||||
|
expect(AddDbUtilities.getGremlinDatabaseUri(properties)).toEqual(
|
||||||
|
"subscriptions/a1/resourceGroups/b1/providers/Microsoft.DocumentDB/databaseAccounts/main/gremlinDatabases/a1-db"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("createGremlinDatabase", () => {
|
||||||
|
it("should utilize resource provider client", () => {
|
||||||
|
const resourceProviderClientSpy = spyOn<any>(AddDbUtilities, "getRpClient");
|
||||||
|
AddDbUtilities.createGremlinDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(resourceProviderClientSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke getGremlinDatabaseUri", () => {
|
||||||
|
const getGremlinDatabaseUriSpy = spyOn<any>(AddDbUtilities, "getGremlinDatabaseUri");
|
||||||
|
AddDbUtilities.createGremlinDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(getGremlinDatabaseUriSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke a put call via resource provider client to create a database and set throughput if shared throughtput is true", () => {
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
AddDbUtilities.createGremlinDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(
|
||||||
|
resourceProviderClientPutAsyncSpy
|
||||||
|
).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a1/resourceGroups/b1/providers/Microsoft.DocumentDB/databaseAccounts/main/gremlinDatabases/a1-db",
|
||||||
|
"2020-04-01",
|
||||||
|
{ properties: { options: { throughput: "50000" }, resource: { id: "a1-db" } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke a put call via resource provider client to create a database and set autopilot if shared throughtput is true and autopilot settings are passed", () => {
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
AddDbUtilities.createGremlinDatabase(armEndpoint, properties, { "x-ms-cosmos-offer-autopilot-tier": "1" });
|
||||||
|
expect(
|
||||||
|
resourceProviderClientPutAsyncSpy
|
||||||
|
).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a1/resourceGroups/b1/providers/Microsoft.DocumentDB/databaseAccounts/main/gremlinDatabases/a1-db",
|
||||||
|
"2020-04-01",
|
||||||
|
{ properties: { options: { "x-ms-cosmos-offer-autopilot-tier": "1" }, resource: { id: "a1-db" } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke a put call via resource provider client to create a database and not set throughput if shared throughtput is false", () => {
|
||||||
|
const properties = {
|
||||||
|
pk: "state",
|
||||||
|
coll: "abc-collection",
|
||||||
|
cd: true,
|
||||||
|
db: "a2-db",
|
||||||
|
st: false,
|
||||||
|
sid: "a2",
|
||||||
|
rg: "c1",
|
||||||
|
dba: "main"
|
||||||
|
};
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
AddDbUtilities.createGremlinDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(
|
||||||
|
resourceProviderClientPutAsyncSpy
|
||||||
|
).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a2/resourceGroups/c1/providers/Microsoft.DocumentDB/databaseAccounts/main/gremlinDatabases/a2-db",
|
||||||
|
"2020-04-01",
|
||||||
|
{ properties: { options: {}, resource: { id: "a2-db" } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("createSqlDatabase", () => {
|
||||||
|
it("should utilize resource provider client", () => {
|
||||||
|
const resourceProviderClientSpy = spyOn<any>(AddDbUtilities, "getRpClient");
|
||||||
|
AddDbUtilities.createSqlDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(resourceProviderClientSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke getSqlDatabaseUri", () => {
|
||||||
|
const getSqlDatabaseUriSpy = spyOn<any>(AddDbUtilities, "getSqlDatabaseUri");
|
||||||
|
AddDbUtilities.createSqlDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(getSqlDatabaseUriSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke a put call via resource provider client to create a database and set throughput if shared throughtput is true", () => {
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
AddDbUtilities.createSqlDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(
|
||||||
|
resourceProviderClientPutAsyncSpy
|
||||||
|
).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a1/resourceGroups/b1/providers/Microsoft.DocumentDB/databaseAccounts/main/sqlDatabases/a1-db",
|
||||||
|
"2020-04-01",
|
||||||
|
{ properties: { options: { throughput: "50000" }, resource: { id: "a1-db" } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke a put call via resource provider client to create a database and set autopilot if shared throughtput is true and autopilot settings are passed", () => {
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
AddDbUtilities.createSqlDatabase(armEndpoint, properties, { "x-ms-cosmos-offer-autopilot-tier": "1" });
|
||||||
|
expect(
|
||||||
|
resourceProviderClientPutAsyncSpy
|
||||||
|
).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a1/resourceGroups/b1/providers/Microsoft.DocumentDB/databaseAccounts/main/sqlDatabases/a1-db",
|
||||||
|
"2020-04-01",
|
||||||
|
{ properties: { options: { "x-ms-cosmos-offer-autopilot-tier": "1" }, resource: { id: "a1-db" } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invoke a put call via resource provider client to create a database and not set throughput if shared throughtput is false", () => {
|
||||||
|
const properties = {
|
||||||
|
pk: "state",
|
||||||
|
coll: "abc-collection",
|
||||||
|
cd: true,
|
||||||
|
db: "a2-db",
|
||||||
|
st: false,
|
||||||
|
sid: "a2",
|
||||||
|
rg: "c1",
|
||||||
|
dba: "main"
|
||||||
|
};
|
||||||
|
const resourceProviderClientPutAsyncSpy = jest.spyOn(ResourceProviderClient.prototype, "putAsync");
|
||||||
|
AddDbUtilities.createSqlDatabase(armEndpoint, properties, undefined);
|
||||||
|
expect(
|
||||||
|
resourceProviderClientPutAsyncSpy
|
||||||
|
).toHaveBeenCalledWith(
|
||||||
|
"subscriptions/a2/resourceGroups/c1/providers/Microsoft.DocumentDB/databaseAccounts/main/sqlDatabases/a2-db",
|
||||||
|
"2020-04-01",
|
||||||
|
{ properties: { options: {}, resource: { id: "a2-db" } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
187
src/Shared/AddDatabaseUtility.ts
Normal file
187
src/Shared/AddDatabaseUtility.ts
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
import * as DataExplorerConstants from "../Common/Constants";
|
||||||
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
|
import { configContext } from "../ConfigContext";
|
||||||
|
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
|
import { HttpStatusCodes } from "../Common/Constants";
|
||||||
|
import { sendMessage } from "../Common/MessageHandler";
|
||||||
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
|
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
|
import { createUpdateCassandraKeyspace } from "../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
|
||||||
|
export class AddDbUtilities {
|
||||||
|
// todo - remove any
|
||||||
|
public static async createMongoDatabaseWithARM(
|
||||||
|
armEndpoint: string,
|
||||||
|
params: DataModels.RpParameters,
|
||||||
|
rpOptions: DataModels.RpOptions
|
||||||
|
): Promise<any> {
|
||||||
|
const rpPayloadToCreateDatabase: DataModels.MongoCreationRequest = {
|
||||||
|
properties: {
|
||||||
|
resource: {
|
||||||
|
id: params.db
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.st) {
|
||||||
|
if (rpOptions) {
|
||||||
|
rpPayloadToCreateDatabase.properties.options = rpOptions;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateDatabase.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await AddDbUtilities.getRpClient<DataModels.CreateDatabaseWithRpResponse>(armEndpoint).putAsync(
|
||||||
|
AddDbUtilities._getMongoDatabaseUri(params),
|
||||||
|
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||||
|
rpPayloadToCreateDatabase
|
||||||
|
);
|
||||||
|
} catch (reason) {
|
||||||
|
AddDbUtilities._handleCreationError(reason, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo - remove any
|
||||||
|
public static async createCassandraKeyspace(
|
||||||
|
params: DataModels.RpParameters,
|
||||||
|
rpOptions: DataModels.RpOptions
|
||||||
|
): Promise<any> {
|
||||||
|
const rpPayloadToCreateKeyspace: DataModels.CreationRequest = {
|
||||||
|
properties: {
|
||||||
|
resource: {
|
||||||
|
id: params.db
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.st) {
|
||||||
|
if (rpOptions) {
|
||||||
|
rpPayloadToCreateKeyspace.properties.options = rpOptions;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateKeyspace.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await createUpdateCassandraKeyspace(
|
||||||
|
userContext.subscriptionId,
|
||||||
|
userContext.resourceGroup,
|
||||||
|
userContext.databaseAccount?.name,
|
||||||
|
params.db,
|
||||||
|
rpPayloadToCreateKeyspace
|
||||||
|
);
|
||||||
|
} catch (reason) {
|
||||||
|
AddDbUtilities._handleCreationError(reason, params, "keyspace");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async createSqlDatabase(
|
||||||
|
armEndpoint: string,
|
||||||
|
params: DataModels.RpParameters,
|
||||||
|
rpOptions: DataModels.RpOptions
|
||||||
|
): Promise<any> {
|
||||||
|
const rpPayloadToCreateSqlDatabase: DataModels.CreationRequest = {
|
||||||
|
properties: {
|
||||||
|
resource: {
|
||||||
|
id: params.db
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (params.st) {
|
||||||
|
if (rpOptions) {
|
||||||
|
rpPayloadToCreateSqlDatabase.properties.options = rpOptions;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateSqlDatabase.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await AddDbUtilities.getRpClient<DataModels.CreateDatabaseWithRpResponse>(armEndpoint).putAsync(
|
||||||
|
AddDbUtilities.getSqlDatabaseUri(params),
|
||||||
|
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||||
|
rpPayloadToCreateSqlDatabase
|
||||||
|
);
|
||||||
|
} catch (reason) {
|
||||||
|
AddDbUtilities._handleCreationError(reason, params, "database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getRpClient<T>(armEndpoint?: string): ResourceProviderClient<T> {
|
||||||
|
return new ResourceProviderClient<T>(armEndpoint || configContext.ARM_ENDPOINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async createGremlinDatabase(
|
||||||
|
armEndpoint: string,
|
||||||
|
params: DataModels.RpParameters,
|
||||||
|
autoPilotSettings: DataModels.RpOptions
|
||||||
|
): Promise<DataModels.CreateDatabaseWithRpResponse> {
|
||||||
|
const rpPayloadToCreateDatabase: DataModels.CreationRequest = {
|
||||||
|
properties: {
|
||||||
|
resource: {
|
||||||
|
id: params.db
|
||||||
|
},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const uri = AddDbUtilities.getGremlinDatabaseUri(params);
|
||||||
|
|
||||||
|
if (params.st) {
|
||||||
|
if (autoPilotSettings) {
|
||||||
|
rpPayloadToCreateDatabase.properties.options = autoPilotSettings;
|
||||||
|
} else {
|
||||||
|
rpPayloadToCreateDatabase.properties.options["throughput"] =
|
||||||
|
params.offerThroughput && params.offerThroughput.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<DataModels.CreateDatabaseWithRpResponse>((resolve, reject) => {
|
||||||
|
AddDbUtilities.getRpClient<DataModels.CreateDatabaseWithRpResponse>(armEndpoint)
|
||||||
|
.putAsync(uri, DataExplorerConstants.ArmApiVersions.publicVersion, rpPayloadToCreateDatabase)
|
||||||
|
.then(
|
||||||
|
() => {
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
reason => {
|
||||||
|
AddDbUtilities._handleCreationError(reason, params);
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _handleCreationError(reason: any, params: DataModels.RpParameters, dbType: string = "database") {
|
||||||
|
NotificationConsoleUtils.logConsoleError(`Error creating ${dbType}: ${JSON.stringify(reason)}, Payload: ${params}`);
|
||||||
|
if (reason.status === HttpStatusCodes.Forbidden) {
|
||||||
|
sendMessage({ type: MessageTypes.ForbiddenError });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error(`Error creating ${dbType}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _getMongoDatabaseUri(params: DataModels.RpParameters): string {
|
||||||
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/mongodbDatabases/${params.db}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _getCassandraKeyspaceUri(params: DataModels.RpParameters): string {
|
||||||
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/cassandraKeyspaces/${params.db}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getGremlinDatabaseUri(params: DataModels.RpParameters): string {
|
||||||
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${params.dba}/gremlinDatabases/${params.db}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getSqlDatabaseUri(params: DataModels.RpParameters): string {
|
||||||
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${params.dba}/sqlDatabases/${params.db}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Defines constants related to logging telemetry. Everything except Action should be kept in sync with the one in the Portal code as much as possible.
|
||||||
|
*
|
||||||
|
* TODO: Move this to ExplorerContracts (265329)
|
||||||
|
*/
|
||||||
|
export class General {
|
||||||
|
public static ExtensionName: string = "Microsoft_Azure_DocumentDB";
|
||||||
|
public static BladeNamePrefix: string = "Extension/Microsoft_Azure_DocumentDB/Blade/";
|
||||||
|
}
|
||||||
|
|
||||||
// Data Explorer specific actions. No need to keep this in sync with the one in Portal.
|
// Data Explorer specific actions. No need to keep this in sync with the one in Portal.
|
||||||
export enum Action {
|
export enum Action {
|
||||||
CollapseTreeNode,
|
CollapseTreeNode,
|
||||||
@@ -73,19 +83,24 @@ export enum Action {
|
|||||||
NotebooksGitHubDisconnect
|
NotebooksGitHubDisconnect
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionModifiers = {
|
export class ActionModifiers {
|
||||||
Start: "start",
|
public static Start: string = "start";
|
||||||
Success: "success",
|
public static Success: string = "success";
|
||||||
Failed: "failed",
|
public static Failed: string = "failed";
|
||||||
Mark: "mark",
|
public static Mark: string = "mark";
|
||||||
Open: "open",
|
public static Open: string = "open";
|
||||||
IFrameReady: "iframeready",
|
public static IFrameReady: string = "iframeready";
|
||||||
Close: "close",
|
public static Close: string = "close";
|
||||||
Submit: "submit",
|
public static Submit: string = "submit";
|
||||||
IndexAll: "index all properties",
|
public static IndexAll: string = "index all properties";
|
||||||
NoIndex: "no indexing",
|
public static NoIndex: string = "no indexing";
|
||||||
Cancel: "cancel"
|
public static Cancel: string = "cancel";
|
||||||
} as const;
|
}
|
||||||
|
|
||||||
|
export class CosmosDBEndpointNames {
|
||||||
|
public static Gateway: string = "CosmosDBGateway";
|
||||||
|
public static ResourceProvider: string = "DocumentDBResourceProvider";
|
||||||
|
}
|
||||||
|
|
||||||
export enum SourceBlade {
|
export enum SourceBlade {
|
||||||
AddCollection,
|
AddCollection,
|
||||||
@@ -111,3 +126,17 @@ export enum SourceBlade {
|
|||||||
ScriptExplorer,
|
ScriptExplorer,
|
||||||
Keys
|
Keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class BladeLoadRequirements {
|
||||||
|
public static collections: string = "Collections";
|
||||||
|
public static collectionsWithOffers: string = "CollectionsWithOffers";
|
||||||
|
public static databaseAccount: string = "DatabaseAccount";
|
||||||
|
public static keys: string = "Keys";
|
||||||
|
public static metrics: string = "Metrics";
|
||||||
|
public static notifications: string = "Notifications";
|
||||||
|
public static singleCollection: string = "SingleCollection";
|
||||||
|
|
||||||
|
public static keysBlade: string[] = [BladeLoadRequirements.databaseAccount, BladeLoadRequirements.keys];
|
||||||
|
public static metricsBlade: string[] = [BladeLoadRequirements.databaseAccount];
|
||||||
|
public static overview: string[] = [BladeLoadRequirements.databaseAccount, BladeLoadRequirements.notifications];
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,124 +8,123 @@ import { userContext } from "../../UserContext";
|
|||||||
/**
|
/**
|
||||||
* Class that persists telemetry data to the portal tables.
|
* Class that persists telemetry data to the portal tables.
|
||||||
*/
|
*/
|
||||||
|
// TODO: Move to a separate Diagnostics folder
|
||||||
|
// TODO: Log telemetry for StorageExplorer case/other clients as well
|
||||||
|
export default class TelemetryProcessor {
|
||||||
|
public static trace(action: Action, actionModifier: string = ActionModifiers.Mark, data?: any): void {
|
||||||
|
sendMessage({
|
||||||
|
type: MessageTypes.TelemetryInfo,
|
||||||
|
data: {
|
||||||
|
action: Action[action],
|
||||||
|
actionModifier: actionModifier,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export function trace(action: Action, actionModifier: string = ActionModifiers.Mark, data?: unknown): void {
|
appInsights.trackEvent({ name: Action[action] }, TelemetryProcessor.getData(data));
|
||||||
sendMessage({
|
|
||||||
type: MessageTypes.TelemetryInfo,
|
|
||||||
data: {
|
|
||||||
action: Action[action],
|
|
||||||
actionModifier: actionModifier,
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
appInsights.trackEvent({ name: Action[action] }, getData(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function traceStart(action: Action, data?: unknown): number {
|
|
||||||
const timestamp: number = Date.now();
|
|
||||||
sendMessage({
|
|
||||||
type: MessageTypes.TelemetryInfo,
|
|
||||||
data: {
|
|
||||||
action: Action[action],
|
|
||||||
actionModifier: ActionModifiers.Start,
|
|
||||||
timestamp: timestamp,
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
appInsights.startTrackEvent(Action[action]);
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function traceSuccess(action: Action, data?: unknown, timestamp?: number): void {
|
|
||||||
sendMessage({
|
|
||||||
type: MessageTypes.TelemetryInfo,
|
|
||||||
data: {
|
|
||||||
action: Action[action],
|
|
||||||
actionModifier: ActionModifiers.Success,
|
|
||||||
timestamp: timestamp || Date.now(),
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
appInsights.stopTrackEvent(Action[action], getData(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function traceFailure(action: Action, data?: unknown, timestamp?: number): void {
|
|
||||||
sendMessage({
|
|
||||||
type: MessageTypes.TelemetryInfo,
|
|
||||||
data: {
|
|
||||||
action: Action[action],
|
|
||||||
actionModifier: ActionModifiers.Failed,
|
|
||||||
timestamp: timestamp || Date.now(),
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
appInsights.stopTrackEvent(Action[action], getData(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function traceCancel(action: Action, data?: unknown, timestamp?: number): void {
|
|
||||||
sendMessage({
|
|
||||||
type: MessageTypes.TelemetryInfo,
|
|
||||||
data: {
|
|
||||||
action: Action[action],
|
|
||||||
actionModifier: ActionModifiers.Cancel,
|
|
||||||
timestamp: timestamp || Date.now(),
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
appInsights.stopTrackEvent(Action[action], getData(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function traceOpen(action: Action, data?: unknown, timestamp?: number): number {
|
|
||||||
const validTimestamp = timestamp || Date.now();
|
|
||||||
sendMessage({
|
|
||||||
type: MessageTypes.TelemetryInfo,
|
|
||||||
data: {
|
|
||||||
action: Action[action],
|
|
||||||
actionModifier: ActionModifiers.Open,
|
|
||||||
timestamp: validTimestamp,
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
appInsights.startTrackEvent(Action[action]);
|
|
||||||
return validTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function traceMark(action: Action, data?: unknown, timestamp?: number): number {
|
|
||||||
const validTimestamp = timestamp || Date.now();
|
|
||||||
sendMessage({
|
|
||||||
type: MessageTypes.TelemetryInfo,
|
|
||||||
data: {
|
|
||||||
action: Action[action],
|
|
||||||
actionModifier: ActionModifiers.Mark,
|
|
||||||
timestamp: validTimestamp,
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
appInsights.startTrackEvent(Action[action]);
|
|
||||||
return validTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getData(data: unknown = {}): { [key: string]: string } | undefined {
|
|
||||||
if (typeof data === "string") {
|
|
||||||
data = { message: data };
|
|
||||||
}
|
}
|
||||||
if (typeof data === "object") {
|
|
||||||
|
public static traceStart(action: Action, data?: any): number {
|
||||||
|
const timestamp: number = Date.now();
|
||||||
|
sendMessage({
|
||||||
|
type: MessageTypes.TelemetryInfo,
|
||||||
|
data: {
|
||||||
|
action: Action[action],
|
||||||
|
actionModifier: ActionModifiers.Start,
|
||||||
|
timestamp: timestamp,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appInsights.startTrackEvent(Action[action]);
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static traceSuccess(action: Action, data?: any, timestamp?: number): void {
|
||||||
|
sendMessage({
|
||||||
|
type: MessageTypes.TelemetryInfo,
|
||||||
|
data: {
|
||||||
|
action: Action[action],
|
||||||
|
actionModifier: ActionModifiers.Success,
|
||||||
|
timestamp: timestamp || Date.now(),
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appInsights.stopTrackEvent(Action[action], TelemetryProcessor.getData(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static traceFailure(action: Action, data?: any, timestamp?: number): void {
|
||||||
|
sendMessage({
|
||||||
|
type: MessageTypes.TelemetryInfo,
|
||||||
|
data: {
|
||||||
|
action: Action[action],
|
||||||
|
actionModifier: ActionModifiers.Failed,
|
||||||
|
timestamp: timestamp || Date.now(),
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appInsights.stopTrackEvent(Action[action], TelemetryProcessor.getData(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static traceCancel(action: Action, data?: any, timestamp?: number): void {
|
||||||
|
sendMessage({
|
||||||
|
type: MessageTypes.TelemetryInfo,
|
||||||
|
data: {
|
||||||
|
action: Action[action],
|
||||||
|
actionModifier: ActionModifiers.Cancel,
|
||||||
|
timestamp: timestamp || Date.now(),
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appInsights.stopTrackEvent(Action[action], TelemetryProcessor.getData(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static traceOpen(action: Action, data?: any, timestamp?: number): number {
|
||||||
|
const validTimestamp = timestamp || Date.now();
|
||||||
|
sendMessage({
|
||||||
|
type: MessageTypes.TelemetryInfo,
|
||||||
|
data: {
|
||||||
|
action: Action[action],
|
||||||
|
actionModifier: ActionModifiers.Open,
|
||||||
|
timestamp: validTimestamp,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appInsights.startTrackEvent(Action[action]);
|
||||||
|
return validTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static traceMark(action: Action, data?: any, timestamp?: number): number {
|
||||||
|
const validTimestamp = timestamp || Date.now();
|
||||||
|
sendMessage({
|
||||||
|
type: MessageTypes.TelemetryInfo,
|
||||||
|
data: {
|
||||||
|
action: Action[action],
|
||||||
|
actionModifier: ActionModifiers.Mark,
|
||||||
|
timestamp: validTimestamp,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appInsights.startTrackEvent(Action[action]);
|
||||||
|
return validTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getData(data: any = {}): any {
|
||||||
|
if (typeof data === "string") {
|
||||||
|
data = { message: data };
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
// TODO: Need to `any` here since the window imports Explorer which can't be in strict mode yet
|
// TODO: Need to `any` here since the window imports Explorer which can't be in strict mode yet
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
authType: (window as any).authType,
|
authType: (window as any).authType,
|
||||||
subscriptionId: userContext.subscriptionId as string,
|
subscriptionId: userContext.subscriptionId,
|
||||||
platform: configContext.platform,
|
platform: configContext.platform,
|
||||||
env: process.env.NODE_ENV as string,
|
env: process.env.NODE_ENV,
|
||||||
...data
|
...data
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { ApplicationInsights } from "@microsoft/applicationinsights-web";
|
import { ApplicationInsights } from "@microsoft/applicationinsights-web";
|
||||||
|
|
||||||
const appInsights = new ApplicationInsights({
|
const appInsights = new ApplicationInsights({
|
||||||
config: {
|
config: {
|
||||||
instrumentationKey: "fa645d97-6237-4656-9559-0ee0cb55ee49",
|
instrumentationKey: "fa645d97-6237-4656-9559-0ee0cb55ee49"
|
||||||
disableFetchTracking: false
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
appInsights.loadAppInsights();
|
appInsights.loadAppInsights();
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/Notificat
|
|||||||
|
|
||||||
const _global = typeof self === "undefined" ? window : self;
|
const _global = typeof self === "undefined" ? window : self;
|
||||||
|
|
||||||
/**
|
// DEPRECATED: Use logConsoleInfo, logConsoleError, logConsoleProgress instead
|
||||||
* @deprecated
|
|
||||||
* Use logConsoleInfo, logConsoleError, logConsoleProgress instead
|
|
||||||
* */
|
|
||||||
export function logConsoleMessage(type: ConsoleDataType, message: string, id?: string): string {
|
export function logConsoleMessage(type: ConsoleDataType, message: string, id?: string): string {
|
||||||
const dataExplorer = _global.dataExplorer;
|
const dataExplorer = _global.dataExplorer;
|
||||||
if (dataExplorer) {
|
if (dataExplorer) {
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ export function getAutoPilotV3SpendHtml(maxAutoPilotThroughputSet: number, isDat
|
|||||||
maxAutoPilotThroughputSet
|
maxAutoPilotThroughputSet
|
||||||
)} GB of data stored, the max RU/s will be automatically upgraded based on the new storage value. <a href='${
|
)} GB of data stored, the max RU/s will be automatically upgraded based on the new storage value. <a href='${
|
||||||
Constants.AutopilotDocumentation.Url
|
Constants.AutopilotDocumentation.Url
|
||||||
}' target='_blank' aria-label='Learn more about autoscale throughput'>Learn more</a>.`;
|
}' target='_blank'>Learn more</a>.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function computeAutoscaleUsagePriceHourly(
|
export function computeAutoscaleUsagePriceHourly(
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
AUTOGENERATED FILE
|
|
||||||
Do not manually edit
|
|
||||||
Run "npm run generateARMClients" to regenerate
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { armRequest } from "../../request";
|
|
||||||
import * as Types from "./types";
|
|
||||||
import { configContext } from "../../../../ConfigContext";
|
|
||||||
const apiVersion = "2020-04-01";
|
|
||||||
|
|
||||||
/* Gets the notebook workspace resources of an existing Cosmos DB account. */
|
|
||||||
export async function listByDatabaseAccount(
|
|
||||||
subscriptionId: string,
|
|
||||||
resourceGroupName: string,
|
|
||||||
accountName: string
|
|
||||||
): Promise<Types.NotebookWorkspaceListResult> {
|
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces`;
|
|
||||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Gets the notebook workspace for a Cosmos DB account. */
|
|
||||||
export async function get(
|
|
||||||
subscriptionId: string,
|
|
||||||
resourceGroupName: string,
|
|
||||||
accountName: string,
|
|
||||||
notebookWorkspaceName: string
|
|
||||||
): Promise<Types.NotebookWorkspace> {
|
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
|
|
||||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Creates the notebook workspace for a Cosmos DB account. */
|
|
||||||
export async function createOrUpdate(
|
|
||||||
subscriptionId: string,
|
|
||||||
resourceGroupName: string,
|
|
||||||
accountName: string,
|
|
||||||
notebookWorkspaceName: string,
|
|
||||||
body: Types.NotebookWorkspaceCreateUpdateParameters
|
|
||||||
): Promise<Types.NotebookWorkspace> {
|
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
|
|
||||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deletes the notebook workspace for a Cosmos DB account. */
|
|
||||||
export async function destroy(
|
|
||||||
subscriptionId: string,
|
|
||||||
resourceGroupName: string,
|
|
||||||
accountName: string,
|
|
||||||
notebookWorkspaceName: string
|
|
||||||
): Promise<void> {
|
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
|
|
||||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieves the connection info for the notebook workspace */
|
|
||||||
export async function listConnectionInfo(
|
|
||||||
subscriptionId: string,
|
|
||||||
resourceGroupName: string,
|
|
||||||
accountName: string,
|
|
||||||
notebookWorkspaceName: string
|
|
||||||
): Promise<Types.NotebookWorkspaceConnectionInfoResult> {
|
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/listConnectionInfo`;
|
|
||||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Regenerates the auth token for the notebook workspace */
|
|
||||||
export async function regenerateAuthToken(
|
|
||||||
subscriptionId: string,
|
|
||||||
resourceGroupName: string,
|
|
||||||
accountName: string,
|
|
||||||
notebookWorkspaceName: string
|
|
||||||
): Promise<void> {
|
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/regenerateAuthToken`;
|
|
||||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Starts the notebook workspace */
|
|
||||||
export async function start(
|
|
||||||
subscriptionId: string,
|
|
||||||
resourceGroupName: string,
|
|
||||||
accountName: string,
|
|
||||||
notebookWorkspaceName: string
|
|
||||||
): Promise<void> {
|
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/start`;
|
|
||||||
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
AUTOGENERATED FILE
|
|
||||||
Do not manually edit
|
|
||||||
Run "npm run generateARMClients" to regenerate
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Parameters to create a notebook workspace resource */
|
|
||||||
export type NotebookWorkspaceCreateUpdateParameters = unknown;
|
|
||||||
|
|
||||||
/* A list of notebook workspace resources */
|
|
||||||
export interface NotebookWorkspaceListResult {
|
|
||||||
/* Array of notebook workspace resources */
|
|
||||||
value?: NotebookWorkspace[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A notebook workspace resource */
|
|
||||||
export type NotebookWorkspace = unknown & {
|
|
||||||
/* Resource properties. */
|
|
||||||
properties?: NotebookWorkspaceProperties;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Properties of a notebook workspace resource. */
|
|
||||||
export interface NotebookWorkspaceProperties {
|
|
||||||
/* Specifies the endpoint of Notebook server. */
|
|
||||||
readonly notebookServerEndpoint?: string;
|
|
||||||
/* Status of the notebook workspace. Possible values are: Creating, Online, Deleting, Failed, Updating. */
|
|
||||||
readonly status?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The connection info for the given notebook workspace */
|
|
||||||
export interface NotebookWorkspaceConnectionInfoResult {
|
|
||||||
/* Specifies auth token used for connecting to Notebook server (uses token-based auth). */
|
|
||||||
readonly authToken?: string;
|
|
||||||
/* Specifies the endpoint of Notebook server. */
|
|
||||||
readonly notebookServerEndpoint?: string;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
import { armRequest } from "./request";
|
import { armRequest } from "./request";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("ARM request", () => {
|
describe("ARM request", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
updateUserContext({
|
||||||
|
authorizationToken: "foo"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should call window.fetch", async () => {
|
it("should call window.fetch", async () => {
|
||||||
window.fetch = jest.fn().mockResolvedValue({
|
window.fetch = jest.fn().mockResolvedValue({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Instead, generate ARM clients that consume this function with stricter typing.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import promiseRetry, { AbortError } from "p-retry";
|
import promiseRetry, { AbortError } from "p-retry";
|
||||||
import { ErrorResponse } from "./generatedClients/2020-04-01-cosmos-db/types";
|
import { ErrorResponse } from "./generatedClients/2020-04-01/types";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
interface ARMError extends Error {
|
interface ARMError extends Error {
|
||||||
@@ -24,11 +24,15 @@ interface Options {
|
|||||||
// TODO: This is very similar to what is happening in ResourceProviderClient.ts. Should probably merge them.
|
// TODO: This is very similar to what is happening in ResourceProviderClient.ts. Should probably merge them.
|
||||||
export async function armRequest<T>({ host, path, apiVersion, method, body: requestBody }: Options): Promise<T> {
|
export async function armRequest<T>({ host, path, apiVersion, method, body: requestBody }: Options): Promise<T> {
|
||||||
const url = new URL(path, host);
|
const url = new URL(path, host);
|
||||||
|
const authHeader = userContext.authorizationToken;
|
||||||
|
if (!authHeader) {
|
||||||
|
throw new Error("No ARM authorization header provided");
|
||||||
|
}
|
||||||
url.searchParams.append("api-version", apiVersion);
|
url.searchParams.append("api-version", apiVersion);
|
||||||
const response = await window.fetch(url.href, {
|
const response = await window.fetch(url.href, {
|
||||||
method,
|
method,
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: userContext.authorizationToken
|
Authorization: authHeader
|
||||||
},
|
},
|
||||||
body: requestBody ? JSON.stringify(requestBody) : undefined
|
body: requestBody ? JSON.stringify(requestBody) : undefined
|
||||||
});
|
});
|
||||||
@@ -71,9 +75,13 @@ interface OperationResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getOperationStatus(operationStatusUrl: string) {
|
async function getOperationStatus(operationStatusUrl: string) {
|
||||||
|
const authHeader = userContext.authorizationToken;
|
||||||
|
if (!authHeader) {
|
||||||
|
throw new Error("No ARM authorization header provided");
|
||||||
|
}
|
||||||
const response = await window.fetch(operationStatusUrl, {
|
const response = await window.fetch(operationStatusUrl, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: userContext.authorizationToken
|
Authorization: authHeader
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user