Merge branch 'master' of https://github.com/Azure/cosmos-explorer into user/balalakshmin/chatbotinit

This commit is contained in:
Bala Lakshmi Narayanasami
2022-07-19 19:48:18 +05:30
33 changed files with 249 additions and 269 deletions

89
package-lock.json generated
View File

@@ -109,9 +109,9 @@
} }
}, },
"@azure/core-rest-pipeline": { "@azure/core-rest-pipeline": {
"version": "1.8.1", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.8.1.tgz", "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.9.0.tgz",
"integrity": "sha512-R/XpxZcDgGbnneEifnsAcjLoR2NCmlDxKDmzd8oi5jx5YEnPE6gsxHQWAk2+uY55Ka717x/fdctyoCYKnumrqw==", "integrity": "sha512-uvM3mY+Vegk0F2r4Eh0yPdsXTUyafTQkeX0USnz1Eyangxm2Bib0w0wkJVZW8fpks7Lcv0ztIdCFTrN7H8uptg==",
"requires": { "requires": {
"@azure/abort-controller": "^1.0.0", "@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0", "@azure/core-auth": "^1.3.0",
@@ -188,12 +188,13 @@
} }
}, },
"@azure/cosmos": { "@azure/cosmos": {
"version": "3.16.2", "version": "3.16.3",
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.2.tgz", "resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.3.tgz",
"integrity": "sha512-sceY5LWj0BHGj8PSyaVCfDRQLVZyoCfIY78kyIROJVEw0k+p9XFs8fhpykN8JklkCftL0WlaVY+X25SQwnhZsw==", "integrity": "sha512-c+znFMHB03QjvLwUfFhASXJn02Ucg0T+sZ4iAC6y7jfjb4SEzxOt3YjvSKAdFzAQa3TMa/Yg9NJEHlRxPSk0/Q==",
"requires": { "requires": {
"@azure/core-auth": "^1.3.0", "@azure/core-auth": "^1.3.0",
"@azure/core-rest-pipeline": "^1.2.0", "@azure/core-rest-pipeline": "^1.2.0",
"@azure/core-tracing": "^1.0.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"fast-json-stable-stringify": "^2.1.0", "fast-json-stable-stringify": "^2.1.0",
"jsbi": "^3.1.3", "jsbi": "^3.1.3",
@@ -205,10 +206,18 @@
"uuid": "^8.3.0" "uuid": "^8.3.0"
}, },
"dependencies": { "dependencies": {
"@azure/core-tracing": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz",
"integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==",
"requires": {
"tslib": "^2.2.0"
}
},
"tslib": { "tslib": {
"version": "2.2.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==" "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
}, },
"universal-user-agent": { "universal-user-agent": {
"version": "6.0.0", "version": "6.0.0",
@@ -8904,9 +8913,9 @@
"integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="
}, },
"are-we-there-yet": { "are-we-there-yet": {
"version": "1.1.5", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==",
"optional": true, "optional": true,
"requires": { "requires": {
"delegates": "^1.0.0", "delegates": "^1.0.0",
@@ -11065,7 +11074,7 @@
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"optional": true "optional": true
}, },
"content-disposition": { "content-disposition": {
@@ -12350,7 +12359,7 @@
"delegates": { "delegates": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"optional": true "optional": true
}, },
"depd": { "depd": {
@@ -12383,7 +12392,7 @@
"detect-libc": { "detect-libc": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"optional": true "optional": true
}, },
"detect-newline": { "detect-newline": {
@@ -21268,9 +21277,9 @@
} }
}, },
"jsbi": { "jsbi": {
"version": "3.1.4", "version": "3.2.5",
"resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.4.tgz", "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz",
"integrity": "sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg==" "integrity": "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ=="
}, },
"jsbn": { "jsbn": {
"version": "0.1.1", "version": "0.1.1",
@@ -23704,9 +23713,9 @@
} }
}, },
"node-abi": { "node-abi": {
"version": "2.26.0", "version": "2.30.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.26.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz",
"integrity": "sha512-ag/Vos/mXXpWLLAYWsAoQdgS+gW7IwvgMLOgqopm/DbzAjazLltzgzpVMsFlgmo9TzG5hGXeaBZx2AI731RIsQ==", "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==",
"optional": true, "optional": true,
"requires": { "requires": {
"semver": "^5.4.1" "semver": "^5.4.1"
@@ -23774,7 +23783,7 @@
"noop-logger": { "noop-logger": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
"integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==",
"optional": true "optional": true
}, },
"nopt": { "nopt": {
@@ -26184,12 +26193,20 @@
}, },
"dependencies": { "dependencies": {
"mkdirp": { "mkdirp": {
"version": "0.5.5", "version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"optional": true, "optional": true,
"requires": { "requires": {
"minimist": "^1.2.5" "minimist": "^1.2.6"
},
"dependencies": {
"minimist": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"optional": true
}
} }
} }
} }
@@ -28286,9 +28303,9 @@
"optional": true "optional": true
}, },
"simple-get": { "simple-get": {
"version": "3.1.0", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
"optional": true, "optional": true,
"requires": { "requires": {
"decompress-response": "^4.2.0", "decompress-response": "^4.2.0",
@@ -31132,18 +31149,18 @@
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q=="
}, },
"which-pm-runs": { "which-pm-runs": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz",
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==",
"optional": true "optional": true
}, },
"wide-align": { "wide-align": {
"version": "1.1.3", "version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"optional": true, "optional": true,
"requires": { "requires": {
"string-width": "^1.0.2 || 2" "string-width": "^1.0.2 || 2 || 3 || 4"
} }
}, },
"wildcard": { "wildcard": {

View File

@@ -5,7 +5,7 @@
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@azure/arm-cosmosdb": "9.1.0", "@azure/arm-cosmosdb": "9.1.0",
"@azure/cosmos": "3.16.2", "@azure/cosmos": "3.16.3",
"@azure/cosmos-language-service": "0.0.5", "@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "1.2.1", "@azure/identity": "1.2.1",
"@azure/ms-rest-nodeauth": "3.0.7", "@azure/ms-rest-nodeauth": "3.0.7",

View File

@@ -24,7 +24,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
); );
try { try {
let collection: DataModels.Collection; let collection: DataModels.Collection;
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) { if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) {
if (params.createNewDatabase) { if (params.createNewDatabase) {
const createDatabaseParams: DataModels.CreateDatabaseParams = { const createDatabaseParams: DataModels.CreateDatabaseParams = {
autoPilotMaxThroughput: params.autoPilotMaxThroughput, autoPilotMaxThroughput: params.autoPilotMaxThroughput,

View File

@@ -25,7 +25,8 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
if (userContext.apiType === "Tables") { if (userContext.apiType === "Tables") {
throw new Error("Creating database resources is not allowed for tables accounts"); throw new Error("Creating database resources is not allowed for tables accounts");
} }
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations const database: DataModels.Database = await (userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations
? createDatabaseWithARM(params) ? createDatabaseWithARM(params)
: createDatabaseWithSDK(params)); : createDatabaseWithSDK(params));

View File

@@ -20,7 +20,11 @@ export async function createStoredProcedure(
): Promise<StoredProcedureDefinition & Resource> { ): Promise<StoredProcedureDefinition & Resource> {
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`); const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
try { try {
const getResponse = await getSqlStoredProcedure( const getResponse = await getSqlStoredProcedure(
userContext.subscriptionId, userContext.subscriptionId,

View File

@@ -14,7 +14,11 @@ export async function createTrigger(
): Promise<TriggerDefinition | SqlTriggerResource> { ): Promise<TriggerDefinition | SqlTriggerResource> {
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`); const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
try { try {
const getResponse = await getSqlTrigger( const getResponse = await getSqlTrigger(
userContext.subscriptionId, userContext.subscriptionId,

View File

@@ -20,7 +20,11 @@ export async function createUserDefinedFunction(
): Promise<UserDefinedFunctionDefinition & Resource> { ): Promise<UserDefinedFunctionDefinition & Resource> {
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`); const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
try { try {
const getResponse = await getSqlUserDefinedFunction( const getResponse = await getSqlUserDefinedFunction(
userContext.subscriptionId, userContext.subscriptionId,

View File

@@ -12,7 +12,7 @@ import { handleError } from "../ErrorHandlingUtils";
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> { export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`); const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) { if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) {
await deleteCollectionWithARM(databaseId, collectionId); await deleteCollectionWithARM(databaseId, collectionId);
} else { } else {
await client().database(databaseId).container(collectionId).delete(); await client().database(databaseId).container(collectionId).delete();

View File

@@ -12,10 +12,7 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`); const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
try { try {
if (userContext.apiType === "Tables") { if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) {
throw new Error("Deleting database resources is not allowed for tables accounts");
}
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
await deleteDatabaseWithARM(databaseId); await deleteDatabaseWithARM(databaseId);
} else { } else {
await client().database(databaseId).delete(); await client().database(databaseId).delete();

View File

@@ -12,7 +12,11 @@ export async function deleteStoredProcedure(
): Promise<void> { ): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`); const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
await deleteSqlStoredProcedure( await deleteSqlStoredProcedure(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -8,7 +8,11 @@ import { handleError } from "../ErrorHandlingUtils";
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> { export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`); const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
await deleteSqlTrigger( await deleteSqlTrigger(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -8,7 +8,11 @@ import { handleError } from "../ErrorHandlingUtils";
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> { export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`); const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
await deleteSqlUserDefinedFunction( await deleteSqlUserDefinedFunction(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -14,7 +14,11 @@ export const readCollectionOffer = async (params: ReadCollectionOfferParams): Pr
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`); const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
return await readCollectionOfferWithARM(params.databaseId, params.collectionId); return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
} }

View File

@@ -13,7 +13,11 @@ import { handleError } from "../ErrorHandlingUtils";
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> { export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`); const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
return await readCollectionsWithARM(databaseId); return await readCollectionsWithARM(databaseId);
} }

View File

@@ -13,7 +13,11 @@ export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promis
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`); const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
return await readDatabaseOfferWithARM(params.databaseId); return await readDatabaseOfferWithARM(params.databaseId);
} }

View File

@@ -13,7 +13,11 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
let databases: DataModels.Database[]; let databases: DataModels.Database[];
const clearMessage = logConsoleProgress(`Querying databases`); const clearMessage = logConsoleProgress(`Querying databases`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
databases = await readDatabasesWithARM(); databases = await readDatabasesWithARM();
} else { } else {
const sdkResponse = await client().databases.readAll().fetchAll(); const sdkResponse = await client().databases.readAll().fetchAll();

View File

@@ -12,7 +12,11 @@ export async function readStoredProcedures(
): Promise<(StoredProcedureDefinition & Resource)[]> { ): Promise<(StoredProcedureDefinition & Resource)[]> {
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`); const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
const rpResponse = await listSqlStoredProcedures( const rpResponse = await listSqlStoredProcedures(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -13,7 +13,11 @@ export async function readTriggers(
): Promise<SqlTriggerResource[] | TriggerDefinition[]> { ): Promise<SqlTriggerResource[] | TriggerDefinition[]> {
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`); const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
const rpResponse = await listSqlTriggers( const rpResponse = await listSqlTriggers(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -11,9 +11,9 @@ export async function readUserDefinedFunctions(
collectionId: string collectionId: string
): Promise<(UserDefinedFunctionDefinition & Resource)[]> { ): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`); const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") { if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") {
const rpResponse = await listSqlUserDefinedFunctions( const rpResponse = await listSqlUserDefinedFunctions(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -33,7 +33,11 @@ export async function updateCollection(
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`); const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") { if (
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection); collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
} else { } else {
const sdkResponse = await client() const sdkResponse = await client()

View File

@@ -56,7 +56,7 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
const clearMessage = logConsoleProgress(`Updating offer for ${offerResourceText}`); const clearMessage = logConsoleProgress(`Updating offer for ${offerResourceText}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) { if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) {
if (params.collectionId) { if (params.collectionId) {
updatedOffer = await updateCollectionOfferWithARM(params); updatedOffer = await updateCollectionOfferWithARM(params);
} else if (userContext.apiType === "Tables") { } else if (userContext.apiType === "Tables") {

View File

@@ -20,9 +20,9 @@ export async function updateStoredProcedure(
): Promise<StoredProcedureDefinition & Resource> { ): Promise<StoredProcedureDefinition & Resource> {
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`); const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
try { try {
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") { if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") {
const getResponse = await getSqlStoredProcedure( const getResponse = await getSqlStoredProcedure(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -13,9 +13,9 @@ export async function updateTrigger(
trigger: SqlTriggerResource trigger: SqlTriggerResource
): Promise<SqlTriggerResource | TriggerDefinition> { ): Promise<SqlTriggerResource | TriggerDefinition> {
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`); const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") { if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") {
const getResponse = await getSqlTrigger( const getResponse = await getSqlTrigger(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -19,9 +19,9 @@ export async function updateUserDefinedFunction(
userDefinedFunction: UserDefinedFunctionDefinition userDefinedFunction: UserDefinedFunctionDefinition
): Promise<UserDefinedFunctionDefinition & Resource> { ): Promise<UserDefinedFunctionDefinition & Resource> {
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`); const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") { if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") {
const getResponse = await getSqlUserDefinedFunction( const getResponse = await getSqlUserDefinedFunction(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -44,7 +44,7 @@ export const createDatabaseContextMenu = (container: Explorer, databaseId: strin
}, },
]; ];
if (userContext.apiType !== "Tables") { if (userContext.apiType !== "Tables" || userContext.features.enableSDKoperations) {
items.push({ items.push({
iconSrc: DeleteDatabaseIcon, iconSrc: DeleteDatabaseIcon,
onClick: () => onClick: () =>

View File

@@ -3,35 +3,25 @@
*/ */
import { Coachmark, DirectionalHint, Image, Link, Stack, TeachingBubbleContent, Text } from "@fluentui/react"; import { Coachmark, DirectionalHint, Image, Link, Stack, TeachingBubbleContent, Text } from "@fluentui/react";
import { useCarousel } from "hooks/useCarousel"; import { useCarousel } from "hooks/useCarousel";
import { useTabs } from "hooks/useTabs"; import { ReactTabKind, useTabs } from "hooks/useTabs";
import * as React from "react"; import * as React from "react";
import { Action } from "Shared/Telemetry/TelemetryConstants"; import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor"; import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import AddDatabaseIcon from "../../../images/AddDatabase.svg";
import NewQueryIcon from "../../../images/AddSqlQuery_16x16.svg";
import NewStoredProcedureIcon from "../../../images/AddStoredProcedure.svg";
import OpenQueryIcon from "../../../images/BrowseQuery.svg";
import ConnectIcon from "../../../images/Connect_color.svg"; import ConnectIcon from "../../../images/Connect_color.svg";
import ContainersIcon from "../../../images/Containers.svg"; import ContainersIcon from "../../../images/Containers.svg";
import LinkIcon from "../../../images/Link_blue.svg"; import LinkIcon from "../../../images/Link_blue.svg";
import NotebookIcon from "../../../images/notebook/Notebook-resource.svg"; import NotebookIcon from "../../../images/notebook/Notebook-resource.svg";
import NotebookColorIcon from "../../../images/Notebooks.svg"; import NotebookColorIcon from "../../../images/Notebooks.svg";
import QuickStartIcon from "../../../images/Quickstart_Lightning.svg"; import QuickStartIcon from "../../../images/Quickstart_Lightning.svg";
import ScaleAndSettingsIcon from "../../../images/Scale_15x15.svg";
import CollectionIcon from "../../../images/tree-collection.svg"; import CollectionIcon from "../../../images/tree-collection.svg";
import { AuthType } from "../../AuthType";
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import * as ViewModels from "../../Contracts/ViewModels";
import { useSidePanel } from "../../hooks/useSidePanel";
import { userContext } from "../../UserContext"; import { userContext } from "../../UserContext";
import { getCollectionName, getDatabaseName } from "../../Utils/APITypeUtils"; import { getCollectionName } from "../../Utils/APITypeUtils";
import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher"; import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher";
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil"; import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity"; import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
import { useNotebook } from "../Notebook/useNotebook"; import { useNotebook } from "../Notebook/useNotebook";
import { AddDatabasePanel } from "../Panes/AddDatabasePanel/AddDatabasePanel";
import { BrowseQueriesPane } from "../Panes/BrowseQueriesPane/BrowseQueriesPane";
import { useDatabases } from "../useDatabases"; import { useDatabases } from "../useDatabases";
import { useSelectedNode } from "../useSelectedNode"; import { useSelectedNode } from "../useSelectedNode";
@@ -234,103 +224,13 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
iconSrc: ConnectIcon, iconSrc: ConnectIcon,
title: "Connect", title: "Connect",
description: "Prefer using your own choice of tooling? Find the connection string you need to connect", description: "Prefer using your own choice of tooling? Find the connection string you need to connect",
onClick: () => useTabs.getState().openAndActivateConnectTab(), onClick: () => useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect),
}; };
heroes.push(connectBtn); heroes.push(connectBtn);
return heroes; return heroes;
} }
private createCommonTaskItems(): SplashScreenItem[] {
const items: SplashScreenItem[] = [];
if (userContext.authType === AuthType.ResourceToken) {
return items;
}
if (!useSelectedNode.getState().isDatabaseNodeOrNoneSelected()) {
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
items.push({
iconSrc: NewQueryIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, undefined);
},
title: "New SQL Query",
description: undefined,
});
} else if (userContext.apiType === "Mongo") {
items.push({
iconSrc: NewQueryIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, undefined);
},
title: "New Query",
description: undefined,
});
}
if (userContext.apiType === "SQL") {
items.push({
iconSrc: OpenQueryIcon,
title: "Open Query",
description: undefined,
onClick: () =>
useSidePanel
.getState()
.openSidePanel("Open Saved Queries", <BrowseQueriesPane explorer={this.container} />),
});
}
if (userContext.apiType !== "Cassandra") {
items.push({
iconSrc: NewStoredProcedureIcon,
title: "New Stored Procedure",
description: undefined,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
},
});
}
/* Scale & Settings */
const isShared = useDatabases.getState().findSelectedDatabase()?.isDatabaseShared();
const label = isShared ? "Settings" : "Scale & Settings";
items.push({
iconSrc: ScaleAndSettingsIcon,
title: label,
description: undefined,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onSettingsClick();
},
});
} else {
items.push({
iconSrc: AddDatabaseIcon,
title: "New " + getDatabaseName(),
description: undefined,
onClick: async () => {
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;
if (throughputCap && throughputCap !== -1) {
await useDatabases.getState().loadAllOffers();
}
useSidePanel
.getState()
.openSidePanel(
"New " + getDatabaseName(),
<AddDatabasePanel explorer={this.container} buttonElement={document.activeElement as HTMLElement} />
);
},
});
}
return items;
}
private decorateOpenCollectionActivity({ databaseId, collectionId }: MostRecentActivity.OpenCollectionItem) { private decorateOpenCollectionActivity({ databaseId, collectionId }: MostRecentActivity.OpenCollectionItem) {
return { return {
iconSrc: CollectionIcon, iconSrc: CollectionIcon,
@@ -372,29 +272,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
}); });
} }
private createTipsItems(): SplashScreenItem[] {
return [
{
iconSrc: undefined,
title: "Data Modeling",
description: "Learn more about modeling",
onClick: () => window.open(SplashScreen.dataModelingUrl),
},
{
iconSrc: undefined,
title: "Cost & Throughput Calculation",
description: "Learn more about cost calculation",
onClick: () => window.open(SplashScreen.throughputEstimatorUrl),
},
{
iconSrc: undefined,
title: "Configure automatic failover",
description: "Learn more about Cosmos DB high-availability",
onClick: () => window.open(SplashScreen.failoverUrl),
},
];
}
private onSplashScreenItemKeyPress(event: React.KeyboardEvent, callback: () => void) { private onSplashScreenItemKeyPress(event: React.KeyboardEvent, callback: () => void) {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) { if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
callback(); callback();

View File

@@ -600,56 +600,43 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
metricsMap.forEach((queryMetrics) => { metricsMap.forEach((queryMetrics) => {
if (queryMetrics) { if (queryMetrics) {
aggregatedMetrics.documentLoadTime = aggregatedMetrics.documentLoadTime =
queryMetrics.documentLoadTime &&
this._normalize(queryMetrics.documentLoadTime.totalMilliseconds()) + this._normalize(queryMetrics.documentLoadTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.documentLoadTime); this._normalize(aggregatedMetrics.documentLoadTime);
aggregatedMetrics.documentWriteTime = aggregatedMetrics.documentWriteTime =
queryMetrics.documentWriteTime &&
this._normalize(queryMetrics.documentWriteTime.totalMilliseconds()) + this._normalize(queryMetrics.documentWriteTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.documentWriteTime); this._normalize(aggregatedMetrics.documentWriteTime);
aggregatedMetrics.indexHitDocumentCount = aggregatedMetrics.indexHitDocumentCount =
queryMetrics.indexHitDocumentCount &&
this._normalize(queryMetrics.indexHitDocumentCount) + this._normalize(queryMetrics.indexHitDocumentCount) +
this._normalize(aggregatedMetrics.indexHitDocumentCount); this._normalize(aggregatedMetrics.indexHitDocumentCount);
aggregatedMetrics.outputDocumentCount = aggregatedMetrics.outputDocumentCount =
queryMetrics.outputDocumentCount &&
this._normalize(queryMetrics.outputDocumentCount) + this._normalize(aggregatedMetrics.outputDocumentCount); this._normalize(queryMetrics.outputDocumentCount) + this._normalize(aggregatedMetrics.outputDocumentCount);
aggregatedMetrics.outputDocumentSize = aggregatedMetrics.outputDocumentSize =
queryMetrics.outputDocumentSize &&
this._normalize(queryMetrics.outputDocumentSize) + this._normalize(aggregatedMetrics.outputDocumentSize); this._normalize(queryMetrics.outputDocumentSize) + this._normalize(aggregatedMetrics.outputDocumentSize);
aggregatedMetrics.indexLookupTime = aggregatedMetrics.indexLookupTime =
queryMetrics.indexLookupTime &&
this._normalize(queryMetrics.indexLookupTime.totalMilliseconds()) + this._normalize(queryMetrics.indexLookupTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.indexLookupTime); this._normalize(aggregatedMetrics.indexLookupTime);
aggregatedMetrics.retrievedDocumentCount = aggregatedMetrics.retrievedDocumentCount =
queryMetrics.retrievedDocumentCount &&
this._normalize(queryMetrics.retrievedDocumentCount) + this._normalize(queryMetrics.retrievedDocumentCount) +
this._normalize(aggregatedMetrics.retrievedDocumentCount); this._normalize(aggregatedMetrics.retrievedDocumentCount);
aggregatedMetrics.retrievedDocumentSize = aggregatedMetrics.retrievedDocumentSize =
queryMetrics.retrievedDocumentSize &&
this._normalize(queryMetrics.retrievedDocumentSize) + this._normalize(queryMetrics.retrievedDocumentSize) +
this._normalize(aggregatedMetrics.retrievedDocumentSize); this._normalize(aggregatedMetrics.retrievedDocumentSize);
aggregatedMetrics.vmExecutionTime = aggregatedMetrics.vmExecutionTime =
queryMetrics.vmExecutionTime &&
this._normalize(queryMetrics.vmExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.vmExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.vmExecutionTime); this._normalize(aggregatedMetrics.vmExecutionTime);
aggregatedMetrics.totalQueryExecutionTime = aggregatedMetrics.totalQueryExecutionTime =
queryMetrics.totalQueryExecutionTime &&
this._normalize(queryMetrics.totalQueryExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.totalQueryExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.totalQueryExecutionTime); this._normalize(aggregatedMetrics.totalQueryExecutionTime);
aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime = aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime =
aggregatedMetrics.runtimeExecutionTimes &&
this._normalize(queryMetrics.runtimeExecutionTimes.queryEngineExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.runtimeExecutionTimes.queryEngineExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime); this._normalize(aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime);
aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime = aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime =
aggregatedMetrics.runtimeExecutionTimes &&
this._normalize(queryMetrics.runtimeExecutionTimes.systemFunctionExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.runtimeExecutionTimes.systemFunctionExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime); this._normalize(aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime);
aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime = aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime =
aggregatedMetrics.runtimeExecutionTimes &&
this._normalize(queryMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime); this._normalize(aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime);
} }
}); });

View File

@@ -1,4 +1,6 @@
import { CollectionTabKind } from "Contracts/ViewModels"; import { CollectionTabKind } from "Contracts/ViewModels";
import Explorer from "Explorer/Explorer";
import { SplashScreen } from "Explorer/SplashScreen/SplashScreen";
import { ConnectTab } from "Explorer/Tabs/ConnectTab"; import { ConnectTab } from "Explorer/Tabs/ConnectTab";
import { useTeachingBubble } from "hooks/useTeachingBubble"; import { useTeachingBubble } from "hooks/useTeachingBubble";
import ko from "knockout"; import ko from "knockout";
@@ -6,28 +8,33 @@ import React, { MutableRefObject, useEffect, useRef, useState } from "react";
import loadingIcon from "../../../images/circular_loader_black_16x16.gif"; import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
import errorIcon from "../../../images/close-black.svg"; import errorIcon from "../../../images/close-black.svg";
import { useObservable } from "../../hooks/useObservable"; import { useObservable } from "../../hooks/useObservable";
import { useTabs } from "../../hooks/useTabs"; import { ReactTabKind, useTabs } from "../../hooks/useTabs";
import TabsBase from "./TabsBase"; import TabsBase from "./TabsBase";
type Tab = TabsBase | (TabsBase & { render: () => JSX.Element }); type Tab = TabsBase | (TabsBase & { render: () => JSX.Element });
export const Tabs = (): JSX.Element => { interface TabsProps {
const { openedTabs, activeTab } = useTabs(); explorer: Explorer;
const isConnectTabOpen = useTabs((state) => state.isConnectTabOpen); }
const isConnectTabActive = useTabs((state) => state.isConnectTabActive);
export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
const { openedTabs, openedReactTabs, activeTab, activeReactTab } = useTabs();
return ( return (
<div className="tabsManagerContainer"> <div className="tabsManagerContainer">
<div id="content" className="flexContainer hideOverflows"> <div id="content" className="flexContainer hideOverflows">
<div className="nav-tabs-margin"> <div className="nav-tabs-margin">
<ul className="nav nav-tabs level navTabHeight" id="navTabs" role="tablist"> <ul className="nav nav-tabs level navTabHeight" id="navTabs" role="tablist">
{isConnectTabOpen && <TabNav key="connect" tab={undefined} active={isConnectTabActive} />} {openedReactTabs.map((tab) => (
<TabNav key={ReactTabKind[tab]} active={activeReactTab === tab} tabKind={tab} />
))}
{openedTabs.map((tab) => ( {openedTabs.map((tab) => (
<TabNav key={tab.tabId} tab={tab} active={activeTab === tab} /> <TabNav key={tab.tabId} tab={tab} active={activeTab === tab} />
))} ))}
</ul> </ul>
</div> </div>
<div className="tabPanesContainer"> <div className="tabPanesContainer">
{isConnectTabActive && <ConnectTab />} {activeReactTab !== undefined && getReactTabContent(activeReactTab, explorer)}
{openedTabs.map((tab) => ( {openedTabs.map((tab) => (
<TabPane key={tab.tabId} tab={tab} active={activeTab === tab} /> <TabPane key={tab.tabId} tab={tab} active={activeTab === tab} />
))} ))}
@@ -37,7 +44,7 @@ export const Tabs = (): JSX.Element => {
); );
}; };
function TabNav({ tab, active }: { tab: Tab; active: boolean }) { function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?: ReactTabKind }) {
const [hovering, setHovering] = useState(false); const [hovering, setHovering] = useState(false);
const focusTab = useRef<HTMLLIElement>() as MutableRefObject<HTMLLIElement>; const focusTab = useRef<HTMLLIElement>() as MutableRefObject<HTMLLIElement>;
const tabId = tab ? tab.tabId : "connect"; const tabId = tab ? tab.tabId : "connect";
@@ -51,8 +58,20 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
<li <li
onMouseOver={() => setHovering(true)} onMouseOver={() => setHovering(true)}
onMouseLeave={() => setHovering(false)} onMouseLeave={() => setHovering(false)}
onClick={() => (tab ? tab.onTabClick() : useTabs.getState().activateConnectTab())} onClick={() => {
onKeyPress={({ nativeEvent: e }) => (tab ? tab.onKeyPressActivate(undefined, e) : onKeyPressConnectTab(e))} if (tab) {
tab.onTabClick();
} else if (tabKind !== undefined) {
useTabs.getState().activateReactTab(tabKind);
}
}}
onKeyPress={({ nativeEvent: e }) => {
if (tab) {
tab.onKeyPressActivate(undefined, e);
} else if (tabKind !== undefined) {
onKeyPressReactTab(e, tabKind);
}
}}
className={active ? "active tabList" : "tabList"} className={active ? "active tabList" : "tabList"}
title={useObservable(tab?.tabPath || ko.observable(""))} title={useObservable(tab?.tabPath || ko.observable(""))}
aria-selected={active} aria-selected={active}
@@ -65,16 +84,18 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
<span className="tabNavContentContainer"> <span className="tabNavContentContainer">
<a data-toggle="tab" href={"#" + tabId} tabIndex={-1}> <a data-toggle="tab" href={"#" + tabId} tabIndex={-1}>
<div className="tab_Content"> <div className="tab_Content">
<span className="statusIconContainer"> <span className="statusIconContainer" style={{ width: tabKind === ReactTabKind.Home ? 0 : 18 }}>
{useObservable(tab?.isExecutionError || ko.observable(false)) && <ErrorIcon tab={tab} active={active} />} {useObservable(tab?.isExecutionError || ko.observable(false)) && <ErrorIcon tab={tab} active={active} />}
{useObservable(tab?.isExecuting || ko.observable(false)) && ( {useObservable(tab?.isExecuting || ko.observable(false)) && (
<img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" /> <img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" />
)} )}
</span> </span>
<span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable("Connect"))}</span> <span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable(ReactTabKind[tabKind]))}</span>
<span className="tabIconSection"> {tabKind !== ReactTabKind.Home && (
<CloseButton tab={tab} active={active} hovering={hovering} /> <span className="tabIconSection">
</span> <CloseButton tab={tab} active={active} hovering={hovering} tabKind={tabKind} />
</span>
)}
</div> </div>
</a> </a>
</span> </span>
@@ -82,14 +103,24 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
); );
} }
const CloseButton = ({ tab, active, hovering }: { tab: Tab; active: boolean; hovering: boolean }) => ( const CloseButton = ({
tab,
active,
hovering,
tabKind,
}: {
tab: Tab;
active: boolean;
hovering: boolean;
tabKind?: ReactTabKind;
}) => (
<span <span
style={{ display: hovering || active ? undefined : "none" }} style={{ display: hovering || active ? undefined : "none" }}
title="Close" title="Close"
role="button" role="button"
aria-label="Close Tab" aria-label="Close Tab"
className="cancelButton" className="cancelButton"
onClick={() => (tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeConnectTab())} onClick={() => (tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind))}
tabIndex={active ? 0 : undefined} tabIndex={active ? 0 : undefined}
onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)} onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)}
> >
@@ -144,9 +175,20 @@ function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
return <div {...attrs} ref={ref} data-bind="html:html" />; return <div {...attrs} ref={ref} data-bind="html:html" />;
} }
const onKeyPressConnectTab = (e: KeyboardEvent): void => { const onKeyPressReactTab = (e: KeyboardEvent, tabKind: ReactTabKind): void => {
if (e.key === "Enter" || e.key === "Space") { if (e.key === "Enter" || e.key === "Space") {
useTabs.getState().activateConnectTab(); useTabs.getState().activateReactTab(tabKind);
e.stopPropagation(); e.stopPropagation();
} }
}; };
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
switch (activeReactTab) {
case ReactTabKind.Connect:
return <ConnectTab />;
case ReactTabKind.Home:
return <SplashScreen explorer={explorer} />;
default:
throw Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
}
};

View File

@@ -1,9 +1,9 @@
import { Link, Stack, TeachingBubble, Text } from "@fluentui/react"; import { Link, Stack, TeachingBubble, Text } from "@fluentui/react";
import { useTabs } from "hooks/useTabs"; import { ReactTabKind, useTabs } from "hooks/useTabs";
import { useTeachingBubble } from "hooks/useTeachingBubble"; import { useTeachingBubble } from "hooks/useTeachingBubble";
import React from "react"; import React from "react";
import { Action } from "Shared/Telemetry/TelemetryConstants"; import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceCancel } from "Shared/Telemetry/TelemetryProcessor"; import { traceCancel, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
export const QuickstartTutorial: React.FC = (): JSX.Element => { export const QuickstartTutorial: React.FC = (): JSX.Element => {
const { step, isSampleDBExpanded, isDocumentsTabOpened, sampleCollection, setStep } = useTeachingBubble(); const { step, isSampleDBExpanded, isDocumentsTabOpened, sampleCollection, setStep } = useTeachingBubble();
@@ -146,7 +146,10 @@ export const QuickstartTutorial: React.FC = (): JSX.Element => {
hasCloseButton hasCloseButton
primaryButtonProps={{ primaryButtonProps={{
text: "Launch connect", text: "Launch connect",
onClick: () => useTabs.getState().openAndActivateConnectTab(), onClick: () => {
traceSuccess(Action.CompleteUITour);
useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect);
},
}} }}
secondaryButtonProps={{ secondaryButtonProps={{
text: "Previous", text: "Previous",

View File

@@ -46,12 +46,10 @@ import "./Explorer/Menus/NotificationConsole/NotificationConsole.less";
import { NotificationConsole } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent"; import { NotificationConsole } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
import "./Explorer/Panes/PanelComponent.less"; import "./Explorer/Panes/PanelComponent.less";
import { SidePanel } from "./Explorer/Panes/PanelContainerComponent"; import { SidePanel } from "./Explorer/Panes/PanelContainerComponent";
import { SplashScreen } from "./Explorer/SplashScreen/SplashScreen";
import "./Explorer/SplashScreen/SplashScreen.less"; import "./Explorer/SplashScreen/SplashScreen.less";
import { Tabs } from "./Explorer/Tabs/Tabs"; import { Tabs } from "./Explorer/Tabs/Tabs";
import { useConfig } from "./hooks/useConfig"; import { useConfig } from "./hooks/useConfig";
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer"; import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
import { useTabs } from "./hooks/useTabs";
import "./Libs/jquery"; import "./Libs/jquery";
import "./Shared/appInsights"; import "./Shared/appInsights";
@@ -59,8 +57,6 @@ initializeIcons();
const App: React.FunctionComponent = () => { const App: React.FunctionComponent = () => {
const [isLeftPaneExpanded, setIsLeftPaneExpanded] = useState<boolean>(true); const [isLeftPaneExpanded, setIsLeftPaneExpanded] = useState<boolean>(true);
const openedTabs = useTabs((state) => state.openedTabs);
const isConnectTabOpen = useTabs((state) => state.isConnectTabOpen);
const isCarouselOpen = useCarousel((state) => state.shouldOpen); const isCarouselOpen = useCarousel((state) => state.shouldOpen);
const config = useConfig(); const config = useConfig();
@@ -104,9 +100,7 @@ const App: React.FunctionComponent = () => {
{/* Collections Tree Collapsed - End */} {/* Collections Tree Collapsed - End */}
</div> </div>
</div> </div>
{/* Collections Tree - End */} <Tabs explorer={explorer} />
{openedTabs.length === 0 && !isConnectTabOpen && <SplashScreen explorer={explorer} />}
<Tabs />
</div> </div>
{/* Collections Tree and Tabs - End */} {/* Collections Tree and Tabs - End */}
<div <div

View File

@@ -130,6 +130,7 @@ export enum Action {
CompleteCarousel, CompleteCarousel,
LaunchUITour, LaunchUITour,
CancelUITour, CancelUITour,
CompleteUITour,
} }
export const ActionModifiers = { export const ActionModifiers = {

View File

@@ -36,7 +36,6 @@ interface UserContext {
readonly accessToken?: string; readonly accessToken?: string;
readonly authorizationToken?: string; readonly authorizationToken?: string;
readonly resourceToken?: string; readonly resourceToken?: string;
readonly useSDKOperations: boolean;
readonly subscriptionType?: SubscriptionType; readonly subscriptionType?: SubscriptionType;
readonly quotaId?: string; readonly quotaId?: string;
// API Type is not yet provided by ARM. You need to manually inspect all the capabilities+kind so we abstract that logic in userContext // API Type is not yet provided by ARM. You need to manually inspect all the capabilities+kind so we abstract that logic in userContext
@@ -61,7 +60,6 @@ export type PortalEnv = "localhost" | "blackforest" | "fairfax" | "mooncake" | "
const ONE_WEEK_IN_MS = 604800000; const ONE_WEEK_IN_MS = 604800000;
const features = extractFeatures(); const features = extractFeatures();
const { enableSDKoperations: useSDKOperations } = features;
const userContext: UserContext = { const userContext: UserContext = {
apiType: "SQL", apiType: "SQL",
@@ -69,7 +67,6 @@ const userContext: UserContext = {
isTryCosmosDBSubscription: false, isTryCosmosDBSubscription: false,
portalEnv: "prod", portalEnv: "prod",
features, features,
useSDKOperations,
addCollectionFlight: CollectionCreation.DefaultAddCollectionDefaultFlight, addCollectionFlight: CollectionCreation.DefaultAddCollectionDefaultFlight,
subscriptionType: CollectionCreation.DefaultSubscriptionType, subscriptionType: CollectionCreation.DefaultSubscriptionType,
collectionCreationDefaults: CollectionCreationDefaults, collectionCreationDefaults: CollectionCreationDefaults,

View File

@@ -6,37 +6,43 @@ import TabsBase from "../Explorer/Tabs/TabsBase";
interface TabsState { interface TabsState {
openedTabs: TabsBase[]; openedTabs: TabsBase[];
openedReactTabs: ReactTabKind[];
activeTab: TabsBase; activeTab: TabsBase;
isConnectTabOpen: boolean; activeReactTab: ReactTabKind;
isConnectTabActive: boolean;
activateTab: (tab: TabsBase) => void; activateTab: (tab: TabsBase) => void;
activateNewTab: (tab: TabsBase) => void; activateNewTab: (tab: TabsBase) => void;
activateReactTab: (tabkind: ReactTabKind) => void;
updateTab: (tab: TabsBase) => void; updateTab: (tab: TabsBase) => void;
getTabs: (tabKind: ViewModels.CollectionTabKind, comparator?: (tab: TabsBase) => boolean) => TabsBase[]; getTabs: (tabKind: ViewModels.CollectionTabKind, comparator?: (tab: TabsBase) => boolean) => TabsBase[];
refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void; refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void;
closeTabsByComparator: (comparator: (tab: TabsBase) => boolean) => void; closeTabsByComparator: (comparator: (tab: TabsBase) => boolean) => void;
closeTab: (tab: TabsBase) => void; closeTab: (tab: TabsBase) => void;
closeAllNotebookTabs: (hardClose: boolean) => void; closeAllNotebookTabs: (hardClose: boolean) => void;
activateConnectTab: () => void; openAndActivateReactTab: (tabKind: ReactTabKind) => void;
openAndActivateConnectTab: () => void; closeReactTab: (tabKind: ReactTabKind) => void;
closeConnectTab: () => void; }
export enum ReactTabKind {
Connect,
Home,
} }
export const useTabs: UseStore<TabsState> = create((set, get) => ({ export const useTabs: UseStore<TabsState> = create((set, get) => ({
openedTabs: [], openedTabs: [],
openedReactTabs: [ReactTabKind.Home],
activeTab: undefined, activeTab: undefined,
isConnectTabOpen: false, activeReactTab: ReactTabKind.Home,
isConnectTabActive: false,
activateTab: (tab: TabsBase): void => { activateTab: (tab: TabsBase): void => {
if (get().openedTabs.some((openedTab) => openedTab.tabId === tab.tabId)) { if (get().openedTabs.some((openedTab) => openedTab.tabId === tab.tabId)) {
set({ activeTab: tab, isConnectTabActive: false }); set({ activeTab: tab, activeReactTab: undefined });
tab.onActivate(); tab.onActivate();
} }
}, },
activateNewTab: (tab: TabsBase): void => { activateNewTab: (tab: TabsBase): void => {
set((state) => ({ openedTabs: [...state.openedTabs, tab], activeTab: tab, isConnectTabActive: false })); set((state) => ({ openedTabs: [...state.openedTabs, tab], activeTab: tab, activeReactTab: undefined }));
tab.onActivate(); tab.onActivate();
}, },
activateReactTab: (tabKind: ReactTabKind): void => set({ activeTab: undefined, activeReactTab: tabKind }),
updateTab: (tab: TabsBase) => { updateTab: (tab: TabsBase) => {
if (get().activeTab?.tabId === tab.tabId) { if (get().activeTab?.tabId === tab.tabId) {
set({ activeTab: tab }); set({ activeTab: tab });
@@ -73,7 +79,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
return true; return true;
}); });
if (updatedTabs.length === 0) { if (updatedTabs.length === 0) {
set({ activeTab: undefined, isConnectTabActive: get().isConnectTabOpen }); set({ activeTab: undefined, activeReactTab: ReactTabKind.Home });
} }
if (tab.tabId === activeTab.tabId && tabIndex !== -1) { if (tab.tabId === activeTab.tabId && tabIndex !== -1) {
@@ -111,21 +117,27 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
}); });
if (get().openedTabs.length === 0) { if (get().openedTabs.length === 0) {
set({ activeTab: undefined, isConnectTabActive: get().isConnectTabOpen }); set({ activeTab: undefined, activeReactTab: ReactTabKind.Home });
} }
} }
}, },
activateConnectTab: () => { openAndActivateReactTab: (tabKind: ReactTabKind) => {
if (get().isConnectTabOpen) { if (get().openedReactTabs.indexOf(tabKind) === -1) {
set({ isConnectTabActive: true, activeTab: undefined }); set((state) => ({
openedReactTabs: [...state.openedReactTabs, tabKind],
}));
} }
set({ activeTab: undefined, activeReactTab: tabKind });
}, },
openAndActivateConnectTab: () => set({ isConnectTabActive: true, isConnectTabOpen: true, activeTab: undefined }), closeReactTab: (tabKind: ReactTabKind) => {
closeConnectTab: () => { const { activeReactTab, openedTabs, openedReactTabs } = get();
const { isConnectTabActive, openedTabs } = get(); if (activeReactTab === tabKind) {
if (isConnectTabActive && openedTabs?.length > 0) { openedTabs?.length > 0
set({ activeTab: openedTabs[0] }); ? set({ activeTab: openedTabs[0], activeReactTab: undefined })
: set({ activeTab: undefined, activeReactTab: openedReactTabs[0] });
} }
set({ isConnectTabActive: false, isConnectTabOpen: false });
set({ openedReactTabs: openedReactTabs.filter((tab: ReactTabKind) => tabKind !== tab) });
}, },
})); }));