mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-21 18:01:39 +00:00
Initial Move from Azure DevOps to GitHub
This commit is contained in:
1143
src/Shared/AddCollectionUtility.test.ts
Normal file
1143
src/Shared/AddCollectionUtility.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
645
src/Shared/AddCollectionUtility.ts
Normal file
645
src/Shared/AddCollectionUtility.ts
Normal file
@@ -0,0 +1,645 @@
|
||||
import * as _ from "underscore";
|
||||
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 { CosmosClient } from "../Common/CosmosClient";
|
||||
import { HttpStatusCodes } from "../Common/Constants";
|
||||
import { MessageHandler } from "../Common/MessageHandler";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
|
||||
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||
import { SubscriptionType } from "../Contracts/ViewModels";
|
||||
|
||||
export class CreateSqlCollectionUtilities {
|
||||
public static createSqlCollection(
|
||||
armEndpoint: string,
|
||||
databaseId: string,
|
||||
analyticalStorageTtl: number,
|
||||
collectionId: string,
|
||||
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,
|
||||
partitionKeyVersion
|
||||
};
|
||||
|
||||
if (params.cd) {
|
||||
return AddDbUtilities.createSqlDatabase(armEndpoint, params, additionalOptions).then(() => {
|
||||
return CreateSqlCollectionUtilities.createSqlCollectionWithARM(armEndpoint, params, additionalOptions);
|
||||
});
|
||||
}
|
||||
return CreateSqlCollectionUtilities.createSqlCollectionWithARM(armEndpoint, params, additionalOptions);
|
||||
}
|
||||
|
||||
public static async createSqlCollectionWithARM(
|
||||
armEndpoint: string,
|
||||
params: DataModels.SqlCollectionParameters,
|
||||
rpOptions: DataModels.RpOptions
|
||||
): Promise<DataModels.CreateCollectionWithRpResponse> {
|
||||
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.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) {
|
||||
MessageHandler.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,
|
||||
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,
|
||||
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.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) {
|
||||
MessageHandler.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) {
|
||||
MessageHandler.sendMessage({ type: MessageTypes.ForbiddenError });
|
||||
return;
|
||||
}
|
||||
throw new Error(`Error creating table`);
|
||||
}
|
||||
}
|
||||
|
||||
public static getDefaultStorage(flight: string, subscriptionType: SubscriptionType): string {
|
||||
const flightDefaults: string = Utilities._getDefaults(flight, subscriptionType).storage;
|
||||
return flightDefaults;
|
||||
}
|
||||
|
||||
public static getDefaultThroughput(flight: string, subscriptionType: SubscriptionType): ThroughputDefaults {
|
||||
const flightDefaults: ThroughputDefaults = Utilities._getDefaults(flight, subscriptionType).throughput;
|
||||
return flightDefaults;
|
||||
}
|
||||
|
||||
public static getMaxRUForStorageOption(
|
||||
subscriptionType = SharedConstants.CollectionCreation.DefaultSubscriptionType,
|
||||
flight = SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight,
|
||||
storageOption: string
|
||||
): number {
|
||||
if (storageOption === SharedConstants.CollectionCreation.storage10Gb) {
|
||||
return SharedConstants.CollectionCreation.DefaultCollectionRUs10K;
|
||||
}
|
||||
|
||||
const defaults = Utilities._getDefaults(flight, subscriptionType);
|
||||
return defaults.throughput.unlimitedmax;
|
||||
}
|
||||
|
||||
public static getMinRUForStorageOption(
|
||||
subscriptionType = SharedConstants.CollectionCreation.DefaultSubscriptionType,
|
||||
flight = SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight,
|
||||
storageOption: string
|
||||
): number {
|
||||
if (storageOption === SharedConstants.CollectionCreation.storage10Gb) {
|
||||
return SharedConstants.CollectionCreation.DefaultCollectionRUs400;
|
||||
}
|
||||
|
||||
const collectionDefaults = Utilities._getCollectionDefaults(subscriptionType, flight);
|
||||
|
||||
return collectionDefaults.throughput.unlimitedmin;
|
||||
}
|
||||
|
||||
public static _getDefaults(flight: string, subscriptionType: SubscriptionType): CollectionDefaults {
|
||||
return Utilities._getCollectionDefaults(subscriptionType, flight);
|
||||
}
|
||||
|
||||
private static _getCollectionDefaults(
|
||||
subscriptionType = SharedConstants.CollectionCreation.DefaultSubscriptionType,
|
||||
flight = SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight
|
||||
): CollectionDefaults {
|
||||
if (!(flight in Utilities._defaultsMap)) {
|
||||
flight = SharedConstants.CollectionCreation.DefaultAddCollectionDefaultFlight;
|
||||
}
|
||||
|
||||
return Utilities._defaultsMap[flight][SubscriptionType[subscriptionType]];
|
||||
}
|
||||
|
||||
private static _exceedsThreshold(container: ViewModels.Explorer): boolean {
|
||||
const unlimitedThreshold: number = 5;
|
||||
|
||||
const databases = (container && container.databases && container.databases()) || [];
|
||||
return _.any(
|
||||
databases,
|
||||
database =>
|
||||
database && database.collections && database.collections() && database.collections().length > unlimitedThreshold
|
||||
);
|
||||
}
|
||||
|
||||
private static _defaultsMap: { [flight: string]: { [subscriptionType: string]: CollectionDefaults } } = {
|
||||
"0": {
|
||||
Benefits: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Free: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
EA: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Internal: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
PAYG: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
Benefits: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Free: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
EA: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Internal: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
PAYG: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
Benefits: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Free: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
EA: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Internal: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
PAYG: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
}
|
||||
},
|
||||
"3": {
|
||||
Benefits: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Free: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
EA: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Internal: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
PAYG: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
}
|
||||
},
|
||||
"20190618.1": {
|
||||
Benefits: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Free: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
EA: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: container =>
|
||||
Utilities._exceedsThreshold(container)
|
||||
? SharedConstants.CollectionCreation.DefaultCollectionRUs1000
|
||||
: SharedConstants.CollectionCreation.DefaultCollectionRUs10K,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs20000
|
||||
}
|
||||
},
|
||||
Internal: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
PAYG: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
}
|
||||
},
|
||||
"20190618.2": {
|
||||
Benefits: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
Free: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
EA: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs1000,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs5000
|
||||
}
|
||||
},
|
||||
Internal: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs100K,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
},
|
||||
PAYG: {
|
||||
storage: SharedConstants.CollectionCreation.storage100Gb,
|
||||
throughput: {
|
||||
fixed: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimited: () => SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
unlimitedmax: SharedConstants.CollectionCreation.DefaultCollectionRUs1Million,
|
||||
unlimitedmin: SharedConstants.CollectionCreation.DefaultCollectionRUs400,
|
||||
shared: SharedConstants.CollectionCreation.DefaultCollectionRUs400
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static _getAzureTableUri(params: DataModels.CreateDatabaseAndCollectionRequest): string {
|
||||
return `subscriptions/${CosmosClient.subscriptionId()}/resourceGroups/${CosmosClient.resourceGroup()}/providers/Microsoft.DocumentDB/databaseAccounts/${
|
||||
CosmosClient.databaseAccount().name
|
||||
}/tables/${params.collectionId}`;
|
||||
}
|
||||
}
|
||||
|
||||
export interface CollectionDefaults {
|
||||
storage: string;
|
||||
throughput: ThroughputDefaults;
|
||||
}
|
||||
|
||||
export interface ThroughputDefaults {
|
||||
fixed: number;
|
||||
unlimited: (explorer: ViewModels.Explorer) => number;
|
||||
unlimitedmax: number;
|
||||
unlimitedmin: number;
|
||||
shared: number;
|
||||
}
|
||||
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-03-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-03-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-03-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-03-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-03-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-03-01",
|
||||
{ properties: { options: {}, resource: { id: "a2-db" } } }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
192
src/Shared/AddDatabaseUtility.ts
Normal file
192
src/Shared/AddDatabaseUtility.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
import * as DataExplorerConstants from "../Common/Constants";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import { config } from "../Config";
|
||||
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { CosmosClient } from "../Common/CosmosClient";
|
||||
import { HttpStatusCodes } from "../Common/Constants";
|
||||
import { MessageHandler } from "../Common/MessageHandler";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
|
||||
import { ResourceProviderClient } from "../ResourceProvider/ResourceProviderClient";
|
||||
|
||||
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(
|
||||
armEndpoint: string,
|
||||
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 AddDbUtilities.getRpClient<DataModels.CreateDatabaseWithRpResponse>(armEndpoint).putAsync(
|
||||
AddDbUtilities._getCassandraKeyspaceUri(params),
|
||||
DataExplorerConstants.ArmApiVersions.publicVersion,
|
||||
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 || config.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.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Error creating ${dbType}: ${JSON.stringify(reason)}, Payload: ${params}`
|
||||
);
|
||||
if (reason.status === HttpStatusCodes.Forbidden) {
|
||||
MessageHandler.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/${
|
||||
CosmosClient.databaseAccount().name
|
||||
}/mongodbDatabases/${params.db}`;
|
||||
}
|
||||
|
||||
private static _getCassandraKeyspaceUri(params: DataModels.RpParameters): string {
|
||||
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${
|
||||
CosmosClient.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}`;
|
||||
}
|
||||
}
|
||||
43
src/Shared/Ajax.ts
Normal file
43
src/Shared/Ajax.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import Q from "q";
|
||||
import $ from "jquery";
|
||||
|
||||
export default class Ajax {
|
||||
public static head<T>(url: string): Q.Promise<any> {
|
||||
return Ajax._ajax(url, "HEAD");
|
||||
}
|
||||
|
||||
public static post<T>(url: string, data?: any): Q.Promise<any> {
|
||||
return Ajax._ajax(url, "POST", data);
|
||||
}
|
||||
|
||||
public static put<T>(url: string, data?: any): Q.Promise<any> {
|
||||
return Ajax._ajax(url, "PUT", data);
|
||||
}
|
||||
|
||||
public static get<T>(url: string, data?: any): Q.Promise<any> {
|
||||
return Ajax._ajax(url, "GET", data);
|
||||
}
|
||||
|
||||
public static Delete<T>(url: string, data?: any): Q.Promise<any> {
|
||||
return Ajax._ajax(url, "DELETE", data);
|
||||
}
|
||||
|
||||
static _ajax<T>(url: string, method: string, data?: any): Q.Promise<any> {
|
||||
return Q($.ajax(url, Ajax._getNetAjaxSettings(url, method, data)));
|
||||
}
|
||||
|
||||
static _getNetAjaxSettings<T>(url: string, method: string, data?: any): JQueryAjaxSettings<T> {
|
||||
var newSettings: JQueryAjaxSettings<T> = {
|
||||
url: url,
|
||||
type: method,
|
||||
cache: false,
|
||||
contentType: "application/json",
|
||||
traditional: true
|
||||
};
|
||||
|
||||
if (!!data) {
|
||||
newSettings.data = typeof data === "string" ? data : JSON.stringify(data || {});
|
||||
}
|
||||
return newSettings;
|
||||
}
|
||||
}
|
||||
348
src/Shared/Constants.ts
Normal file
348
src/Shared/Constants.ts
Normal file
@@ -0,0 +1,348 @@
|
||||
import { SubscriptionType } from "../Contracts/ViewModels";
|
||||
|
||||
export const hoursInAMonth = 730;
|
||||
export class AutoscalePricing {
|
||||
public static MonthlyPricing = {
|
||||
default: {
|
||||
singleMaster: {
|
||||
Currency: "USD",
|
||||
CurrencySign: "$",
|
||||
Standard: {
|
||||
StartingPrice: 24,
|
||||
PricePerRU: 0.09,
|
||||
PricePerGB: 0.25
|
||||
}
|
||||
},
|
||||
multiMaster: {
|
||||
Currency: "USD",
|
||||
CurrencySign: "$",
|
||||
Standard: {
|
||||
StartingPrice: 24,
|
||||
PricePerRU: 0.12,
|
||||
PricePerGB: 0.25
|
||||
}
|
||||
}
|
||||
},
|
||||
mooncake: {
|
||||
singleMaster: {
|
||||
Currency: "RMB",
|
||||
CurrencySign: "¥",
|
||||
Standard: {
|
||||
StartingPrice: 152,
|
||||
PricePerRU: 0.57,
|
||||
PricePerGB: 2.576
|
||||
}
|
||||
},
|
||||
multiMaster: {
|
||||
Currency: "RMB",
|
||||
CurrencySign: "¥",
|
||||
Standard: {
|
||||
StartingPrice: 152,
|
||||
PricePerRU: 0.76,
|
||||
PricePerGB: 2.576
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static HourlyPricing = {
|
||||
default: {
|
||||
singleMaster: {
|
||||
Currency: "USD",
|
||||
CurrencySign: "$",
|
||||
Standard: {
|
||||
StartingPrice: 24 / hoursInAMonth,
|
||||
PricePerRU: 0.00012,
|
||||
PricePerGB: 0.25 / hoursInAMonth
|
||||
}
|
||||
},
|
||||
multiMaster: {
|
||||
Currency: "USD",
|
||||
CurrencySign: "$",
|
||||
Standard: {
|
||||
StartingPrice: 24 / hoursInAMonth,
|
||||
PricePerRU: 0.00016,
|
||||
PricePerGB: 0.25 / hoursInAMonth
|
||||
}
|
||||
}
|
||||
},
|
||||
mooncake: {
|
||||
singleMaster: {
|
||||
Currency: "RMB",
|
||||
CurrencySign: "¥",
|
||||
Standard: {
|
||||
StartingPrice: AutoscalePricing.MonthlyPricing.mooncake.singleMaster.Standard.StartingPrice / hoursInAMonth, // per hour
|
||||
PricePerRU: 0.000765,
|
||||
PricePerGB: AutoscalePricing.MonthlyPricing.mooncake.singleMaster.Standard.PricePerGB / hoursInAMonth
|
||||
}
|
||||
},
|
||||
multiMaster: {
|
||||
Currency: "RMB",
|
||||
CurrencySign: "¥",
|
||||
Standard: {
|
||||
StartingPrice: AutoscalePricing.MonthlyPricing.mooncake.multiMaster.Standard.StartingPrice / hoursInAMonth, // per hour
|
||||
PricePerRU: 0.00102,
|
||||
PricePerGB: AutoscalePricing.MonthlyPricing.mooncake.multiMaster.Standard.PricePerGB / hoursInAMonth
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class OfferPricing {
|
||||
public static MonthlyPricing = {
|
||||
default: {
|
||||
Currency: "USD",
|
||||
CurrencySign: "$",
|
||||
S1Price: 25,
|
||||
S2Price: 50,
|
||||
S3Price: 100,
|
||||
Standard: {
|
||||
StartingPrice: 24,
|
||||
PricePerRU: 0.06,
|
||||
PricePerGB: 0.25
|
||||
}
|
||||
},
|
||||
mooncake: {
|
||||
Currency: "RMB",
|
||||
CurrencySign: "¥",
|
||||
S1Price: 110.3,
|
||||
S2Price: 220.6,
|
||||
S3Price: 441.2,
|
||||
Standard: {
|
||||
StartingPrice: 152,
|
||||
PricePerRU: 0.3794,
|
||||
PricePerGB: 2.576
|
||||
}
|
||||
}
|
||||
};
|
||||
public static HourlyPricing = {
|
||||
default: {
|
||||
Currency: "USD",
|
||||
CurrencySign: "$",
|
||||
S1Price: 0.0336,
|
||||
S2Price: 0.0672,
|
||||
S3Price: 0.1344,
|
||||
Standard: {
|
||||
StartingPrice: 24 / hoursInAMonth, // per hour
|
||||
PricePerRU: 0.00008,
|
||||
PricePerRUPM: (10 * 2) / 1000 / hoursInAMonth, // preview price: $2 per 1000 RU/m per month -> 100 RU/s
|
||||
PricePerGB: 0.25 / hoursInAMonth
|
||||
}
|
||||
},
|
||||
mooncake: {
|
||||
Currency: "RMB",
|
||||
CurrencySign: "¥",
|
||||
S1Price: 0.15,
|
||||
S2Price: 0.3,
|
||||
S3Price: 0.6,
|
||||
Standard: {
|
||||
StartingPrice: OfferPricing.MonthlyPricing.mooncake.Standard.StartingPrice / hoursInAMonth, // per hour
|
||||
PricePerRU: 0.00051,
|
||||
PricePerRUPM: (10 * 20) / 1000 / hoursInAMonth, // preview price: 20rmb per 1000 RU/m per month -> 100 RU/s
|
||||
PricePerGB: OfferPricing.MonthlyPricing.mooncake.Standard.PricePerGB / hoursInAMonth
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class GeneralResources {
|
||||
public static loadingText: string = "Loading...";
|
||||
}
|
||||
|
||||
export class CollectionCreation {
|
||||
// TODO generate these values based on Product\Services\Documents\ImageStore\GatewayApplication\Settings.xml
|
||||
public static readonly MinRUPerPartitionBelow7Partitions: number = 400;
|
||||
public static readonly MinRU7PartitionsTo25Partitions: number = 2500;
|
||||
public static readonly MinRUPerPartitionAbove25Partitions: number = 100;
|
||||
public static readonly MaxRUPerPartition: number = 10000;
|
||||
public static readonly MaxRUPMPerPartition: number = 5000;
|
||||
public static readonly MinPartitionedCollectionRUs: number = 2500;
|
||||
|
||||
public static readonly NumberOfPartitionsInFixedCollection: number = 1;
|
||||
public static readonly NumberOfPartitionsInUnlimitedCollection: number = 10;
|
||||
|
||||
public static storage10Gb: string = "10";
|
||||
public static storage100Gb: string = "100";
|
||||
|
||||
public static readonly DefaultCollectionRUs1000: number = 1000;
|
||||
public static readonly DefaultCollectionRUs10K: number = 10000;
|
||||
public static readonly DefaultCollectionRUs400: number = 400;
|
||||
public static readonly DefaultCollectionRUs2000: number = 2000;
|
||||
public static readonly DefaultCollectionRUs2500: number = 2500;
|
||||
public static readonly DefaultCollectionRUs5000: number = 5000;
|
||||
public static readonly DefaultCollectionRUs15000: number = 15000;
|
||||
public static readonly DefaultCollectionRUs20000: number = 20000;
|
||||
public static readonly DefaultCollectionRUs25000: number = 25000;
|
||||
public static readonly DefaultCollectionRUs100K: number = 100000;
|
||||
public static readonly DefaultCollectionRUs1Million: number = 1000000;
|
||||
|
||||
public static readonly DefaultAddCollectionDefaultFlight: string = "0";
|
||||
public static readonly DefaultSubscriptionType: SubscriptionType = SubscriptionType.Free;
|
||||
|
||||
public static readonly TablesAPIDefaultDatabase: string = "TablesDB";
|
||||
}
|
||||
|
||||
export class IndexingPolicies {
|
||||
public static SharedDatabaseDefault = {
|
||||
indexingMode: "consistent",
|
||||
automatic: true,
|
||||
includedPaths: <any>[],
|
||||
excludedPaths: [
|
||||
{
|
||||
path: "/*"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
public static AllPropertiesIndexed = {
|
||||
indexingMode: "consistent",
|
||||
automatic: true,
|
||||
includedPaths: [
|
||||
{
|
||||
path: "/*",
|
||||
indexes: [
|
||||
{
|
||||
kind: "Range",
|
||||
dataType: "Number",
|
||||
precision: -1
|
||||
},
|
||||
{
|
||||
kind: "Range",
|
||||
dataType: "String",
|
||||
precision: -1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
excludedPaths: <any>[]
|
||||
};
|
||||
|
||||
// todo - remove mongo indexing policy ticket # 616274
|
||||
public static Mongo = {
|
||||
indexingMode: "consistent",
|
||||
automatic: true,
|
||||
includedPaths: [
|
||||
{
|
||||
path: "/*",
|
||||
indexes: [
|
||||
{
|
||||
kind: "Range",
|
||||
dataType: "Number",
|
||||
precision: -1
|
||||
},
|
||||
{
|
||||
kind: "Range",
|
||||
dataType: "String",
|
||||
precision: -1
|
||||
},
|
||||
{
|
||||
kind: "Spatial",
|
||||
dataType: "Point"
|
||||
},
|
||||
{
|
||||
kind: "Spatial",
|
||||
dataType: "LineString"
|
||||
},
|
||||
{
|
||||
kind: "Spatial",
|
||||
dataType: "Polygon"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
excludedPaths: <any>[]
|
||||
};
|
||||
}
|
||||
|
||||
export class SubscriptionUtilMappings {
|
||||
// TODO: Expose this through a web API from the portal
|
||||
public static SubscriptionTypeMap: { [key: string]: SubscriptionType } = {
|
||||
"AAD_2015-09-01": SubscriptionType.Free,
|
||||
"AzureDynamics_2014-09-01": SubscriptionType.Free,
|
||||
"AzureInOpen_2014-09-01": SubscriptionType.EA,
|
||||
"AzurePass_2014-09-01": SubscriptionType.Free,
|
||||
"BackupStorage_2014-09-01": SubscriptionType.PAYG,
|
||||
"BizSpark_2014-09-01": SubscriptionType.Benefits,
|
||||
"BizSparkPlus_2014-09-01": SubscriptionType.Benefits,
|
||||
"CSP_2015-05-01": SubscriptionType.EA,
|
||||
"Default_2014-09-01": SubscriptionType.PAYG,
|
||||
"DevEssentials_2016-01-01": SubscriptionType.Benefits,
|
||||
"DreamSpark_2015-02-01": SubscriptionType.Benefits,
|
||||
"EnterpriseAgreement_2014-09-01": SubscriptionType.EA,
|
||||
"FreeTrial_2014-09-01": SubscriptionType.Free,
|
||||
"Internal_2014-09-01": SubscriptionType.Internal,
|
||||
"LegacyMonetaryCommitment_2014-09-01": SubscriptionType.EA,
|
||||
"LightweightTrial_2016-09-01": SubscriptionType.Free,
|
||||
"MonetaryCommitment_2015-05-01": SubscriptionType.EA,
|
||||
"MPN_2014-09-01": SubscriptionType.Benefits,
|
||||
"MSDN_2014-09-01": SubscriptionType.Benefits,
|
||||
"MSDNDevTest_2014-09-01": SubscriptionType.Benefits,
|
||||
"PayAsYouGo_2014-09-01": SubscriptionType.PAYG,
|
||||
"Sponsored_2016-01-01": SubscriptionType.Benefits
|
||||
};
|
||||
|
||||
public static FreeTierSubscriptionIds: string[] = [
|
||||
"b8f2ff04-0a81-4cf9-95ef-5828d16981d2",
|
||||
"39b1fdff-e5b2-4f83-adb4-33cb3aabf5ea",
|
||||
"41f6d14d-ece1-46e4-942c-02c00d67f7d6",
|
||||
"11dc62e3-77dc-4ef5-a46b-480ec6caa8fe",
|
||||
"199d0919-60bd-448e-b64d-8461a0fe9747",
|
||||
"a57b6849-d443-44cf-a3b7-7dd07ead9401"
|
||||
];
|
||||
}
|
||||
|
||||
export class Offers {
|
||||
public static offerTypeS1: string = "S1";
|
||||
public static offerTypeS2: string = "S2";
|
||||
public static offerTypeS3: string = "S3";
|
||||
public static offerTypeStandard: string = "Standard";
|
||||
}
|
||||
|
||||
export class OfferThoughput {
|
||||
public static offerS1Throughput: number = 250;
|
||||
public static offerS2Throughput: number = 1000;
|
||||
public static offerS3Throughput: number = 2500;
|
||||
}
|
||||
|
||||
export class OfferVersions {
|
||||
public static offerV1: string = "V1";
|
||||
public static offerV2: string = "V2";
|
||||
}
|
||||
|
||||
export class InvalidOffers {
|
||||
public static offerTypeInvalid: string = "Invalid";
|
||||
public static offerTypeError: string = "Loading Error";
|
||||
}
|
||||
|
||||
export class SpecTypes {
|
||||
public static collection: string = "DocumentDbCollection";
|
||||
}
|
||||
|
||||
export class CurrencyCodes {
|
||||
public static usd: string = "USD";
|
||||
public static rmb: string = "RMB";
|
||||
}
|
||||
|
||||
export class ColorSchemes {
|
||||
public static standard: string = "mediumBlue";
|
||||
public static legacy: string = "yellowGreen";
|
||||
}
|
||||
|
||||
export class FeatureIds {
|
||||
public static storage: string = "storage";
|
||||
public static sla: string = "sla";
|
||||
public static partitioned: string = "partitioned";
|
||||
public static singlePartitioned: string = "singlePartition";
|
||||
public static legacySinglePartitioned: string = "legacySinglePartition";
|
||||
}
|
||||
|
||||
export class FeatureIconNames {
|
||||
public static storage: string = "SSD";
|
||||
public static sla: string = "Monitoring";
|
||||
public static productionReady: string = "ProductionReadyDb";
|
||||
}
|
||||
|
||||
export class AutopilotDocumentation {
|
||||
public static Url: string = "https://aka.ms/cosmos-autoscale-info";
|
||||
}
|
||||
133
src/Shared/DefaultExperienceUtility.test.ts
Normal file
133
src/Shared/DefaultExperienceUtility.test.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import * as Constants from "../Common/Constants";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
import { DefaultExperienceUtility } from "./DefaultExperienceUtility";
|
||||
|
||||
describe("Default Experience Utility", () => {
|
||||
describe("getDefaultExperienceFromApiKind()", () => {
|
||||
function runScenario(apiKind: number, expectedExperience: string): void {
|
||||
const resolvedExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(apiKind);
|
||||
expect(resolvedExperience).toEqual(expectedExperience);
|
||||
}
|
||||
|
||||
describe("On SQL", () => {
|
||||
it("should return SQL", () => runScenario(DataModels.ApiKind.SQL, Constants.DefaultAccountExperience.DocumentDB));
|
||||
});
|
||||
|
||||
describe("On MongoDB", () => {
|
||||
it("should return MongoDB", () =>
|
||||
runScenario(DataModels.ApiKind.MongoDB, Constants.DefaultAccountExperience.MongoDB));
|
||||
});
|
||||
|
||||
describe("On Table", () => {
|
||||
it("should return Table", () => runScenario(DataModels.ApiKind.Table, Constants.DefaultAccountExperience.Table));
|
||||
});
|
||||
|
||||
describe("On Cassandra", () => {
|
||||
it("should return Cassandra", () =>
|
||||
runScenario(DataModels.ApiKind.Cassandra, Constants.DefaultAccountExperience.Cassandra));
|
||||
});
|
||||
|
||||
describe("On Graph", () => {
|
||||
it("should return Graph", () => runScenario(DataModels.ApiKind.Graph, Constants.DefaultAccountExperience.Graph));
|
||||
});
|
||||
|
||||
describe("On unknown", () => {
|
||||
it("should return Default", () => runScenario(-1, Constants.DefaultAccountExperience.Default));
|
||||
});
|
||||
});
|
||||
|
||||
describe("getApiKindFromDefaultExperience()", () => {
|
||||
function runScenario(defaultExperience: string, expectedApiKind: number): void {
|
||||
const resolvedApiKind = DefaultExperienceUtility.getApiKindFromDefaultExperience(defaultExperience);
|
||||
expect(resolvedApiKind).toEqual(expectedApiKind);
|
||||
}
|
||||
|
||||
describe("On SQL", () => {
|
||||
it("should return SQL", () => runScenario(Constants.DefaultAccountExperience.DocumentDB, DataModels.ApiKind.SQL));
|
||||
});
|
||||
|
||||
describe("On MongoDB", () => {
|
||||
it("should return MongoDB", () =>
|
||||
runScenario(Constants.DefaultAccountExperience.MongoDB, DataModels.ApiKind.MongoDB));
|
||||
});
|
||||
|
||||
describe("On Table", () => {
|
||||
it("should return Table", () => runScenario(Constants.DefaultAccountExperience.Table, DataModels.ApiKind.Table));
|
||||
});
|
||||
|
||||
describe("On Cassandra", () => {
|
||||
it("should return Cassandra", () =>
|
||||
runScenario(Constants.DefaultAccountExperience.Cassandra, DataModels.ApiKind.Cassandra));
|
||||
});
|
||||
|
||||
describe("On Graph", () => {
|
||||
it("should return Graph", () => runScenario(Constants.DefaultAccountExperience.Graph, DataModels.ApiKind.Graph));
|
||||
});
|
||||
|
||||
describe("On null", () => {
|
||||
it("should return SQL", () => runScenario(null, DataModels.ApiKind.SQL));
|
||||
});
|
||||
});
|
||||
|
||||
describe("getDefaultExperienceFromDatabaseAccount()", () => {
|
||||
function runScenario(databaseAccount: ViewModels.DatabaseAccount, expectedDefaultExperience: string): void {
|
||||
const resolvedExperience = DefaultExperienceUtility.getDefaultExperienceFromDatabaseAccount(databaseAccount);
|
||||
expect(resolvedExperience).toEqual(expectedDefaultExperience);
|
||||
}
|
||||
|
||||
const databaseAccountWithWrongTagsAndCapabilities: ViewModels.DatabaseAccount = {
|
||||
id: "test",
|
||||
kind: "GlobalDocumentDB",
|
||||
name: "test",
|
||||
location: "somewhere",
|
||||
type: "DocumentDB",
|
||||
tags: {
|
||||
defaultExperience: "Gremlin (graph)"
|
||||
},
|
||||
properties: {
|
||||
documentEndpoint: "",
|
||||
cassandraEndpoint: "",
|
||||
gremlinEndpoint: "",
|
||||
tableEndpoint: "",
|
||||
capabilities: [
|
||||
{
|
||||
name: Constants.CapabilityNames.EnableGremlin,
|
||||
description: "something"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const databaseAccountWithApiKind: ViewModels.DatabaseAccount = {
|
||||
id: "test",
|
||||
kind: Constants.AccountKind.MongoDB,
|
||||
name: "test",
|
||||
location: "somewhere",
|
||||
type: "DocumentDB",
|
||||
tags: {},
|
||||
properties: {
|
||||
documentEndpoint: "",
|
||||
cassandraEndpoint: "",
|
||||
gremlinEndpoint: "",
|
||||
tableEndpoint: "",
|
||||
capabilities: [
|
||||
{
|
||||
name: Constants.CapabilityNames.EnableGremlin,
|
||||
description: "something"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
describe("Disregard tags", () => {
|
||||
it("should return Graph", () =>
|
||||
runScenario(databaseAccountWithWrongTagsAndCapabilities, Constants.DefaultAccountExperience.Graph));
|
||||
});
|
||||
|
||||
describe("Respect Kind over capabilities", () => {
|
||||
it("should return MongoDB", () =>
|
||||
runScenario(databaseAccountWithApiKind, Constants.DefaultAccountExperience.MongoDB));
|
||||
});
|
||||
});
|
||||
});
|
||||
139
src/Shared/DefaultExperienceUtility.ts
Normal file
139
src/Shared/DefaultExperienceUtility.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import * as _ from "underscore";
|
||||
import * as Constants from "../Common/Constants";
|
||||
import * as DataModels from "../Contracts/DataModels";
|
||||
import * as ViewModels from "../Contracts/ViewModels";
|
||||
|
||||
export class DefaultExperienceUtility {
|
||||
public static getDefaultExperienceFromDatabaseAccount(databaseAccount: ViewModels.DatabaseAccount): string {
|
||||
if (!databaseAccount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const kind: string =
|
||||
databaseAccount && databaseAccount.kind && databaseAccount.kind && databaseAccount.kind.toLowerCase();
|
||||
const capabilities: ViewModels.Capability[] =
|
||||
(databaseAccount.properties && databaseAccount.properties.capabilities) || [];
|
||||
|
||||
return DefaultExperienceUtility._getDefaultExperience(kind, capabilities);
|
||||
}
|
||||
|
||||
public static getApiKindFromDefaultExperience(defaultExperience: string): DataModels.ApiKind {
|
||||
if (!defaultExperience) {
|
||||
return DataModels.ApiKind.SQL;
|
||||
}
|
||||
|
||||
switch (defaultExperience) {
|
||||
case Constants.DefaultAccountExperience.DocumentDB:
|
||||
return DataModels.ApiKind.SQL;
|
||||
case Constants.DefaultAccountExperience.MongoDB:
|
||||
case Constants.DefaultAccountExperience.ApiForMongoDB:
|
||||
return DataModels.ApiKind.MongoDB;
|
||||
case Constants.DefaultAccountExperience.Table:
|
||||
return DataModels.ApiKind.Table;
|
||||
case Constants.DefaultAccountExperience.Cassandra:
|
||||
return DataModels.ApiKind.Cassandra;
|
||||
case Constants.DefaultAccountExperience.Graph:
|
||||
return DataModels.ApiKind.Graph;
|
||||
default:
|
||||
return DataModels.ApiKind.SQL;
|
||||
}
|
||||
}
|
||||
|
||||
public static getDefaultExperienceFromApiKind(apiKind: DataModels.ApiKind): string {
|
||||
if (apiKind == null) {
|
||||
return Constants.DefaultAccountExperience.Default;
|
||||
}
|
||||
|
||||
switch (apiKind) {
|
||||
case DataModels.ApiKind.SQL:
|
||||
return Constants.DefaultAccountExperience.DocumentDB;
|
||||
case DataModels.ApiKind.MongoDB:
|
||||
case DataModels.ApiKind.MongoDBCompute:
|
||||
return Constants.DefaultAccountExperience.MongoDB;
|
||||
case DataModels.ApiKind.Table:
|
||||
return Constants.DefaultAccountExperience.Table;
|
||||
case DataModels.ApiKind.Cassandra:
|
||||
return Constants.DefaultAccountExperience.Cassandra;
|
||||
case DataModels.ApiKind.Graph:
|
||||
return Constants.DefaultAccountExperience.Graph;
|
||||
default:
|
||||
return Constants.DefaultAccountExperience.Default;
|
||||
}
|
||||
}
|
||||
|
||||
private static _getDefaultExperience(kind: string, capabilities: ViewModels.Capability[]): string {
|
||||
const defaultDefaultExperience: string = Constants.DefaultAccountExperience.DocumentDB;
|
||||
const defaultExperienceFromKind: string = DefaultExperienceUtility._getDefaultExperienceFromAccountKind(kind);
|
||||
const defaultExperienceFromCapabilities: string = DefaultExperienceUtility._getDefaultExperienceFromAccountCapabilities(
|
||||
capabilities
|
||||
);
|
||||
|
||||
if (!!defaultExperienceFromKind) {
|
||||
return defaultExperienceFromKind;
|
||||
}
|
||||
|
||||
if (!!defaultExperienceFromCapabilities) {
|
||||
return defaultExperienceFromCapabilities;
|
||||
}
|
||||
|
||||
return defaultDefaultExperience;
|
||||
}
|
||||
|
||||
private static _getDefaultExperienceFromAccountKind(kind: string): string {
|
||||
if (!kind) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (kind.toLowerCase() === Constants.AccountKind.MongoDB.toLowerCase()) {
|
||||
return Constants.DefaultAccountExperience.MongoDB;
|
||||
}
|
||||
|
||||
if (kind.toLowerCase() === Constants.AccountKind.Parse.toLowerCase()) {
|
||||
return Constants.DefaultAccountExperience.MongoDB;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static _getDefaultExperienceFromAccountCapabilities(capabilities: ViewModels.Capability[]): string {
|
||||
if (!capabilities) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Array.isArray(capabilities)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const enableTable: ViewModels.Capability = DefaultExperienceUtility._findCapability(
|
||||
capabilities,
|
||||
Constants.CapabilityNames.EnableTable
|
||||
);
|
||||
if (enableTable) {
|
||||
return Constants.DefaultAccountExperience.Table;
|
||||
}
|
||||
|
||||
const enableGremlin: ViewModels.Capability = DefaultExperienceUtility._findCapability(
|
||||
capabilities,
|
||||
Constants.CapabilityNames.EnableGremlin
|
||||
);
|
||||
if (enableGremlin) {
|
||||
return Constants.DefaultAccountExperience.Graph;
|
||||
}
|
||||
|
||||
const enableCassandra: ViewModels.Capability = DefaultExperienceUtility._findCapability(
|
||||
capabilities,
|
||||
Constants.CapabilityNames.EnableCassandra
|
||||
);
|
||||
if (enableCassandra) {
|
||||
return Constants.DefaultAccountExperience.Cassandra;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static _findCapability(capabilities: ViewModels.Capability[], capabilityName: string): ViewModels.Capability {
|
||||
return _.find(capabilities, (capability: ViewModels.Capability) => {
|
||||
return capability && capability.name && capability.name.toLowerCase() === capabilityName.toLowerCase();
|
||||
});
|
||||
}
|
||||
}
|
||||
22
src/Shared/ExplorerSettings.ts
Normal file
22
src/Shared/ExplorerSettings.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as Constants from "../Common/Constants";
|
||||
import { LocalStorageUtility, StorageKey } from "./StorageUtility";
|
||||
|
||||
export class ExplorerSettings {
|
||||
public static createDefaultSettings() {
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.ActualItemPerPage, Constants.Queries.itemsPerPage);
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.CustomItemPerPage, Constants.Queries.itemsPerPage);
|
||||
LocalStorageUtility.setEntryString(StorageKey.IsCrossPartitionQueryEnabled, "true");
|
||||
LocalStorageUtility.setEntryNumber(
|
||||
StorageKey.MaxDegreeOfParellism,
|
||||
Constants.Queries.DefaultMaxDegreeOfParallelism
|
||||
);
|
||||
}
|
||||
|
||||
public static hasSettingsDefined(): boolean {
|
||||
return (
|
||||
LocalStorageUtility.hasItem(StorageKey.ActualItemPerPage) &&
|
||||
LocalStorageUtility.hasItem(StorageKey.IsCrossPartitionQueryEnabled) &&
|
||||
LocalStorageUtility.hasItem(StorageKey.MaxDegreeOfParellism)
|
||||
);
|
||||
}
|
||||
}
|
||||
47
src/Shared/PriceEstimateCalculator.ts
Normal file
47
src/Shared/PriceEstimateCalculator.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import * as Constants from "./Constants";
|
||||
|
||||
export function computeRUUsagePrice(serverId: string, rupmEnabled: boolean, requestUnits: number): string {
|
||||
if (serverId === "mooncake") {
|
||||
let ruCharge = requestUnits * Constants.OfferPricing.HourlyPricing.mooncake.Standard.PricePerRU,
|
||||
rupmCharge = rupmEnabled ? requestUnits * Constants.OfferPricing.HourlyPricing.mooncake.Standard.PricePerRUPM : 0;
|
||||
return (
|
||||
calculateEstimateNumber(ruCharge + rupmCharge) + " " + Constants.OfferPricing.HourlyPricing.mooncake.Currency
|
||||
);
|
||||
}
|
||||
|
||||
let ruCharge = requestUnits * Constants.OfferPricing.HourlyPricing.default.Standard.PricePerRU,
|
||||
rupmCharge = rupmEnabled ? requestUnits * Constants.OfferPricing.HourlyPricing.default.Standard.PricePerRUPM : 0;
|
||||
return calculateEstimateNumber(ruCharge + rupmCharge) + " " + Constants.OfferPricing.HourlyPricing.default.Currency;
|
||||
}
|
||||
|
||||
export function computeStorageUsagePrice(serverId: string, storageUsedRoundUpToGB: number): string {
|
||||
if (serverId === "mooncake") {
|
||||
let storageCharge = storageUsedRoundUpToGB * Constants.OfferPricing.HourlyPricing.mooncake.Standard.PricePerGB;
|
||||
return calculateEstimateNumber(storageCharge) + " " + Constants.OfferPricing.HourlyPricing.mooncake.Currency;
|
||||
}
|
||||
|
||||
let storageCharge = storageUsedRoundUpToGB * Constants.OfferPricing.HourlyPricing.default.Standard.PricePerGB;
|
||||
return calculateEstimateNumber(storageCharge) + " " + Constants.OfferPricing.HourlyPricing.default.Currency;
|
||||
}
|
||||
|
||||
export function computeDisplayUsageString(usageInKB: number): string {
|
||||
let usageInMB = usageInKB / 1024,
|
||||
usageInGB = usageInMB / 1024,
|
||||
displayUsageString =
|
||||
usageInGB > 0.1
|
||||
? usageInGB.toFixed(2) + " GB"
|
||||
: usageInMB > 0.1
|
||||
? usageInMB.toFixed(2) + " MB"
|
||||
: usageInKB.toFixed(2) + " KB";
|
||||
return displayUsageString;
|
||||
}
|
||||
|
||||
export function usageInGB(usageInKB: number): number {
|
||||
let usageInMB = usageInKB / 1024,
|
||||
usageInGB = usageInMB / 1024;
|
||||
return Math.ceil(usageInGB);
|
||||
}
|
||||
|
||||
function calculateEstimateNumber(n: number): string {
|
||||
return n >= 1 ? n.toFixed(2) : n.toPrecision(2);
|
||||
}
|
||||
55
src/Shared/StorageUtility.test.ts
Normal file
55
src/Shared/StorageUtility.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { StorageKey, LocalStorageUtility, SessionStorageUtility } from "./StorageUtility";
|
||||
|
||||
describe("Storage Utility", () => {
|
||||
beforeAll(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it("should find a value that exist in local storage", () => {
|
||||
localStorage.setItem(StorageKey[StorageKey.ActualItemPerPage], "123");
|
||||
expect(LocalStorageUtility.hasItem(StorageKey.ActualItemPerPage)).toBe(true);
|
||||
});
|
||||
|
||||
it("should not find a value that does not exist in local storage", () => {
|
||||
expect(LocalStorageUtility.hasItem(StorageKey.ActualItemPerPage)).toBe(false);
|
||||
});
|
||||
|
||||
it("should place the string key/value pair into local storage", () => {
|
||||
LocalStorageUtility.setEntryString(StorageKey.ActualItemPerPage, "abc");
|
||||
expect(localStorage.getItem(StorageKey[StorageKey.ActualItemPerPage])).toEqual("abc");
|
||||
});
|
||||
|
||||
it("should place the number key/value pair into local storage as a string", () => {
|
||||
LocalStorageUtility.setEntryNumber(StorageKey.ActualItemPerPage, 123);
|
||||
expect(localStorage.getItem(StorageKey[StorageKey.ActualItemPerPage])).toEqual("123");
|
||||
});
|
||||
|
||||
it("should retrieve the string value", () => {
|
||||
localStorage.setItem(StorageKey[StorageKey.ActualItemPerPage], "123");
|
||||
expect(LocalStorageUtility.getEntryString(StorageKey.ActualItemPerPage)).toEqual("123");
|
||||
});
|
||||
|
||||
it("should retrieve the string value and convert to number", () => {
|
||||
localStorage.setItem(StorageKey[StorageKey.ActualItemPerPage], "123");
|
||||
const result = LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage);
|
||||
expect(Number(result)).toEqual(123);
|
||||
});
|
||||
|
||||
it("should remove the entry from local storage if exists", () => {
|
||||
localStorage.setItem(StorageKey[StorageKey.ActualItemPerPage], "123");
|
||||
LocalStorageUtility.removeEntry(StorageKey.ActualItemPerPage);
|
||||
|
||||
expect(LocalStorageUtility.getEntryString(StorageKey.ActualItemPerPage)).toBeNull();
|
||||
});
|
||||
|
||||
it("should remove the entry from session storage if exists", () => {
|
||||
sessionStorage.setItem(StorageKey[StorageKey.ActualItemPerPage], "123");
|
||||
SessionStorageUtility.removeEntry(StorageKey.ActualItemPerPage);
|
||||
|
||||
expect(LocalStorageUtility.getEntryString(StorageKey.ActualItemPerPage)).toBeNull();
|
||||
});
|
||||
});
|
||||
76
src/Shared/StorageUtility.ts
Normal file
76
src/Shared/StorageUtility.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { StringUtility } from "./StringUtility";
|
||||
|
||||
export class LocalStorageUtility {
|
||||
public static hasItem(key: StorageKey): boolean {
|
||||
return !!localStorage.getItem(StorageKey[key]);
|
||||
}
|
||||
|
||||
public static getEntryString(key: StorageKey): string {
|
||||
return localStorage.getItem(StorageKey[key]);
|
||||
}
|
||||
|
||||
public static getEntryNumber(key: StorageKey): number {
|
||||
return StringUtility.toNumber(localStorage.getItem(StorageKey[key]));
|
||||
}
|
||||
|
||||
public static getEntryBoolean(key: StorageKey): boolean {
|
||||
return StringUtility.toBoolean(localStorage.getItem(StorageKey[key]));
|
||||
}
|
||||
|
||||
public static setEntryString(key: StorageKey, value: string): void {
|
||||
localStorage.setItem(StorageKey[key], value);
|
||||
}
|
||||
|
||||
public static removeEntry(key: StorageKey): void {
|
||||
return localStorage.removeItem(StorageKey[key]);
|
||||
}
|
||||
|
||||
public static setEntryNumber(key: StorageKey, value: number): void {
|
||||
localStorage.setItem(StorageKey[key], value.toString());
|
||||
}
|
||||
|
||||
public static setEntryBoolean(key: StorageKey, value: boolean): void {
|
||||
localStorage.setItem(StorageKey[key], value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
export class SessionStorageUtility {
|
||||
public static hasItem(key: StorageKey): boolean {
|
||||
return !!sessionStorage.getItem(StorageKey[key]);
|
||||
}
|
||||
|
||||
public static getEntryString(key: StorageKey): string {
|
||||
return sessionStorage.getItem(StorageKey[key]);
|
||||
}
|
||||
|
||||
public static getEntryNumber(key: StorageKey): number {
|
||||
return StringUtility.toNumber(localStorage.getItem(StorageKey[key]));
|
||||
}
|
||||
|
||||
public static removeEntry(key: StorageKey): void {
|
||||
return sessionStorage.removeItem(StorageKey[key]);
|
||||
}
|
||||
|
||||
public static setEntryString(key: StorageKey, value: string): void {
|
||||
sessionStorage.setItem(StorageKey[key], value);
|
||||
}
|
||||
|
||||
public static setEntryNumber(key: StorageKey, value: number): void {
|
||||
sessionStorage.setItem(StorageKey[key], value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
export enum StorageKey {
|
||||
ActualItemPerPage,
|
||||
CustomItemPerPage,
|
||||
DatabaseAccountId,
|
||||
EncryptedKeyToken,
|
||||
IsCrossPartitionQueryEnabled,
|
||||
MaxDegreeOfParellism,
|
||||
IsGraphAutoVizDisabled,
|
||||
TenantId,
|
||||
MostRecentActivity,
|
||||
SetPartitionKeyUndefined,
|
||||
NotebookMetadata,
|
||||
NotebookName
|
||||
}
|
||||
15
src/Shared/StringUtility.test.ts
Normal file
15
src/Shared/StringUtility.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { StringUtility } from "./StringUtility";
|
||||
|
||||
describe("String utility", () => {
|
||||
it("Convert to integer from string", () => {
|
||||
expect(StringUtility.toNumber("123")).toBe(123);
|
||||
});
|
||||
|
||||
it("Convert to boolean from string (true)", () => {
|
||||
expect(StringUtility.toBoolean("true")).toBe(true);
|
||||
});
|
||||
|
||||
it("Convert to boolean from string (false)", () => {
|
||||
expect(StringUtility.toBoolean("false")).toBe(false);
|
||||
});
|
||||
});
|
||||
9
src/Shared/StringUtility.ts
Normal file
9
src/Shared/StringUtility.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export class StringUtility {
|
||||
public static toNumber(num: string): number {
|
||||
return Number(num);
|
||||
}
|
||||
|
||||
public static toBoolean(valueStr: string): boolean {
|
||||
return valueStr === "true";
|
||||
}
|
||||
}
|
||||
155
src/Shared/Telemetry/TelemetryConstants.ts
Normal file
155
src/Shared/Telemetry/TelemetryConstants.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Defines constants related to logging telemetry. This file should be kept in sync with the one in the portal extension 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/";
|
||||
}
|
||||
|
||||
/**
|
||||
* This is to be kept in sync with the one in portal. Please update the one in the portal if you add/remove any entry.
|
||||
*/
|
||||
export enum Action {
|
||||
CollapseTreeNode,
|
||||
CreateDatabaseAccount,
|
||||
CreateAzureFunction,
|
||||
CreateCollection,
|
||||
CreateDocument,
|
||||
CreateStoredProcedure,
|
||||
CreateTrigger,
|
||||
CreateUDF,
|
||||
DeleteCollection,
|
||||
DeleteDatabase,
|
||||
DeleteDocument,
|
||||
DownloadQuickstart,
|
||||
ExpandTreeNode,
|
||||
ExecuteQuery,
|
||||
HasFeature,
|
||||
GetVNETServices,
|
||||
InitializeAccountLocationFromResourceGroup,
|
||||
InitializeDataExplorer,
|
||||
LoadDatabaseAccount,
|
||||
LoadCollections,
|
||||
LoadDatabases,
|
||||
LoadMetrics,
|
||||
LoadOffers,
|
||||
LoadSingleCollectionWithOfferAndStatistics,
|
||||
MongoShell,
|
||||
OpenMetrics,
|
||||
ContextualPane,
|
||||
ScaleThroughput,
|
||||
SelectItem,
|
||||
SwitchQuickstartPlatform,
|
||||
Tab,
|
||||
UpdateDocument,
|
||||
UpdateRegions,
|
||||
UpdateSettings,
|
||||
UpdateStoredProcedure,
|
||||
UpdateTrigger,
|
||||
UpdateUDF,
|
||||
ViewWarning,
|
||||
LoadBlade,
|
||||
LoadResourceTree,
|
||||
LoadMetricsTab,
|
||||
AccountLevelThroughput,
|
||||
CreateDatabase,
|
||||
ResolveConflict,
|
||||
DeleteConflict,
|
||||
SaveQuery,
|
||||
SetupSavedQueries,
|
||||
LoadSavedQuery,
|
||||
DeleteSavedQuery,
|
||||
ConnectEncryptionToken,
|
||||
SignInAad,
|
||||
SignOutAad,
|
||||
FetchTenants,
|
||||
FetchSubscriptions,
|
||||
FetchAccounts,
|
||||
GetAccountKeys,
|
||||
LoadingStatus,
|
||||
AccountSwitch,
|
||||
SubscriptionSwitch,
|
||||
TenantSwitch,
|
||||
DefaultTenantSwitch,
|
||||
ResetNotebookWorkspace,
|
||||
CreateNotebookWorkspace,
|
||||
NotebookErrorNotification,
|
||||
CreateSparkCluster,
|
||||
UpdateSparkCluster,
|
||||
DeleteSparkCluster,
|
||||
LibraryManage,
|
||||
ClusterLibraryManage,
|
||||
ModifyOptionForThroughputWithSharedDatabase,
|
||||
EnableAzureSynapseLink,
|
||||
CreateNewNotebook,
|
||||
OpenSampleNotebook,
|
||||
ExecuteCell,
|
||||
ExecuteAllCells,
|
||||
NotebookEnabled,
|
||||
NotebooksGitHubConnect,
|
||||
NotebooksGitHubAuthorize,
|
||||
NotebooksGitHubManualRepoAdd,
|
||||
NotebooksGitHubManageRepo,
|
||||
NotebooksGitHubCommit,
|
||||
NotebooksGitHubDisconnect
|
||||
}
|
||||
|
||||
export class ActionModifiers {
|
||||
public static Start: string = "start";
|
||||
public static Success: string = "success";
|
||||
public static Failed: string = "failed";
|
||||
public static Mark: string = "mark";
|
||||
public static Open: string = "open";
|
||||
public static IFrameReady: string = "iframeready";
|
||||
public static Close: string = "close";
|
||||
public static Submit: string = "submit";
|
||||
public static IndexAll: string = "index all properties";
|
||||
public static NoIndex: string = "no indexing";
|
||||
public static Cancel: string = "cancel";
|
||||
}
|
||||
|
||||
export class CosmosDBEndpointNames {
|
||||
public static Gateway: string = "CosmosDBGateway";
|
||||
public static ResourceProvider: string = "DocumentDBResourceProvider";
|
||||
}
|
||||
|
||||
export enum SourceBlade {
|
||||
AddCollection,
|
||||
AzureFunction,
|
||||
BrowseCollectionBlade,
|
||||
CassandraAccountCreateBlade,
|
||||
CollectionSetting,
|
||||
DatabaseAccountCreateBlade,
|
||||
DataExplorer,
|
||||
DeleteCollection,
|
||||
DeleteDatabase,
|
||||
DocumentExplorer,
|
||||
FirewallVNETBlade,
|
||||
Metrics,
|
||||
NonDocumentDBAccountCreateBlade,
|
||||
OverviewBlade,
|
||||
QueryExplorer,
|
||||
Quickstart,
|
||||
ReaderWarning,
|
||||
ResourceMenu,
|
||||
RpcProvider,
|
||||
ScaleCollection,
|
||||
ScriptExplorer,
|
||||
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];
|
||||
}
|
||||
136
src/Shared/Telemetry/TelemetryProcessor.ts
Normal file
136
src/Shared/Telemetry/TelemetryProcessor.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { Action, ActionModifiers } from "./TelemetryConstants";
|
||||
import { MessageHandler } from "../../Common/MessageHandler";
|
||||
import { MessageTypes } from "../../Contracts/ExplorerContracts";
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
MessageHandler.sendMessage({
|
||||
type: MessageTypes.TelemetryInfo,
|
||||
data: {
|
||||
action: Action[action],
|
||||
actionModifier: actionModifier,
|
||||
data: JSON.stringify(data)
|
||||
}
|
||||
});
|
||||
|
||||
const appInsights: Microsoft.ApplicationInsights.IAppInsights = (<any>window).appInsights;
|
||||
if (!appInsights) {
|
||||
return;
|
||||
}
|
||||
appInsights.trackEvent(Action[action], data);
|
||||
}
|
||||
|
||||
public static traceStart(action: Action, data?: any): number {
|
||||
const timestamp: number = Date.now();
|
||||
MessageHandler.sendMessage({
|
||||
type: MessageTypes.TelemetryInfo,
|
||||
data: {
|
||||
action: Action[action],
|
||||
actionModifier: ActionModifiers.Start,
|
||||
timestamp: timestamp,
|
||||
data: JSON.stringify(data)
|
||||
}
|
||||
});
|
||||
|
||||
const appInsights: Microsoft.ApplicationInsights.IAppInsights = (<any>window).appInsights;
|
||||
if (appInsights) {
|
||||
appInsights.startTrackEvent(Action[action]);
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public static traceSuccess(action: Action, data?: any, timestamp?: number): void {
|
||||
MessageHandler.sendMessage({
|
||||
type: MessageTypes.TelemetryInfo,
|
||||
data: {
|
||||
action: Action[action],
|
||||
actionModifier: ActionModifiers.Success,
|
||||
timestamp: timestamp || Date.now(),
|
||||
data: JSON.stringify(data)
|
||||
}
|
||||
});
|
||||
|
||||
const appInsights: Microsoft.ApplicationInsights.IAppInsights = (<any>window).appInsights;
|
||||
if (!appInsights) {
|
||||
return;
|
||||
}
|
||||
appInsights.stopTrackEvent(Action[action], data);
|
||||
}
|
||||
|
||||
public static traceFailure(action: Action, data?: any, timestamp?: number): void {
|
||||
MessageHandler.sendMessage({
|
||||
type: MessageTypes.TelemetryInfo,
|
||||
data: {
|
||||
action: Action[action],
|
||||
actionModifier: ActionModifiers.Failed,
|
||||
timestamp: timestamp || Date.now(),
|
||||
data: JSON.stringify(data)
|
||||
}
|
||||
});
|
||||
|
||||
const appInsights: Microsoft.ApplicationInsights.IAppInsights = (<any>window).appInsights;
|
||||
if (!appInsights) {
|
||||
return;
|
||||
}
|
||||
appInsights.stopTrackEvent(Action[action], data);
|
||||
}
|
||||
|
||||
public static traceCancel(action: Action, data?: any, timestamp?: number): void {
|
||||
MessageHandler.sendMessage({
|
||||
type: MessageTypes.TelemetryInfo,
|
||||
data: {
|
||||
action: Action[action],
|
||||
actionModifier: ActionModifiers.Cancel,
|
||||
timestamp: timestamp || Date.now(),
|
||||
data: JSON.stringify(data)
|
||||
}
|
||||
});
|
||||
|
||||
const appInsights: Microsoft.ApplicationInsights.IAppInsights = (<any>window).appInsights;
|
||||
if (!appInsights) {
|
||||
return;
|
||||
}
|
||||
appInsights.stopTrackEvent(Action[action], data);
|
||||
}
|
||||
|
||||
public static traceOpen(action: Action, data?: any, timestamp?: number): number {
|
||||
MessageHandler.sendMessage({
|
||||
type: MessageTypes.TelemetryInfo,
|
||||
data: {
|
||||
action: Action[action],
|
||||
actionModifier: ActionModifiers.Open,
|
||||
timestamp: timestamp || Date.now(),
|
||||
data: JSON.stringify(data)
|
||||
}
|
||||
});
|
||||
|
||||
const appInsights: Microsoft.ApplicationInsights.IAppInsights = (<any>window).appInsights;
|
||||
if (appInsights) {
|
||||
appInsights.startTrackEvent(Action[action]);
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public static traceMark(action: Action, data?: any, timestamp?: number): number {
|
||||
MessageHandler.sendMessage({
|
||||
type: MessageTypes.TelemetryInfo,
|
||||
data: {
|
||||
action: Action[action],
|
||||
actionModifier: ActionModifiers.Mark,
|
||||
timestamp: timestamp || Date.now(),
|
||||
data: JSON.stringify(data)
|
||||
}
|
||||
});
|
||||
|
||||
const appInsights: Microsoft.ApplicationInsights.IAppInsights = (<any>window).appInsights;
|
||||
if (appInsights) {
|
||||
appInsights.startTrackEvent(Action[action]);
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
10
src/Shared/appInsights.ts
Normal file
10
src/Shared/appInsights.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ApplicationInsights } from "@microsoft/applicationinsights-web";
|
||||
const appInsights = new ApplicationInsights({
|
||||
config: {
|
||||
instrumentationKey: "fa645d97-6237-4656-9559-0ee0cb55ee49"
|
||||
}
|
||||
});
|
||||
appInsights.loadAppInsights();
|
||||
appInsights.trackPageView(); // Manually call trackPageView to establish the current user/session/pageview
|
||||
|
||||
export { appInsights };
|
||||
Reference in New Issue
Block a user