diff --git a/src/Common/DataAccessUtilityBase.ts b/src/Common/DataAccessUtilityBase.ts index b816aea63..d18efcf6c 100644 --- a/src/Common/DataAccessUtilityBase.ts +++ b/src/Common/DataAccessUtilityBase.ts @@ -7,7 +7,6 @@ import { Resource } from "@azure/cosmos"; import { RequestOptions } from "@azure/cosmos/dist-esm"; -import Q from "q"; import { configContext, Platform } from "../ConfigContext"; import * as DataModels from "../Contracts/DataModels"; import { MessageTypes } from "../Contracts/ExplorerContracts"; @@ -39,18 +38,17 @@ export function getCommonQueryOptions(options: FeedOptions): any { return options; } -export function queryDocuments( +export async function queryDocuments( databaseId: string, containerId: string, query: string, options: any -): Q.Promise> { +): Promise> { options = getCommonQueryOptions(options); - const documentsIterator = client() + return client() .database(databaseId) .container(containerId) .items.query(query, options); - return Q(documentsIterator); } export function getPartitionKeyHeaderForConflict(conflictId: ConflictId): Object { @@ -76,17 +74,15 @@ export function updateDocument( collection: ViewModels.CollectionBase, documentId: DocumentId, newDocument: any -): Q.Promise { +): Promise { const partitionKey = documentId.partitionKeyValue; - return Q( - client() - .database(collection.databaseId) - .container(collection.id()) - .item(documentId.id(), partitionKey) - .replace(newDocument) - .then(response => response.resource) - ); + return client() + .database(collection.databaseId) + .container(collection.id()) + .item(documentId.id(), partitionKey) + .replace(newDocument) + .then(response => response.resource); } export function executeStoredProcedure( @@ -94,105 +90,89 @@ export function executeStoredProcedure( storedProcedure: StoredProcedure, partitionKeyValue: any, params: any[] -): Q.Promise { - // TODO remove this deferred. Kept it because of timeout code at bottom of function - const deferred = Q.defer(); - - client() - .database(collection.databaseId) - .container(collection.id()) - .scripts.storedProcedure(storedProcedure.id()) - .execute(partitionKeyValue, params, { enableScriptLogging: true }) - .then(response => - deferred.resolve({ +): Promise { + return Promise.race([ + client() + .database(collection.databaseId) + .container(collection.id()) + .scripts.storedProcedure(storedProcedure.id()) + .execute(partitionKeyValue, params, { enableScriptLogging: true }) + .then(response => ({ result: response.resource, scriptLogs: response.headers[Constants.HttpHeaders.scriptLogResults] - }) + })), + new Promise((_, reject) => + setTimeout( + () => reject(`Request timed out while executing stored procedure ${storedProcedure.id()}`), + Constants.ClientDefaults.requestTimeoutMs + ) ) - .catch(error => deferred.reject(error)); - - return deferred.promise.timeout( - Constants.ClientDefaults.requestTimeoutMs, - `Request timed out while executing stored procedure ${storedProcedure.id()}` - ); + ]); } -export function createDocument(collection: ViewModels.CollectionBase, newDocument: any): Q.Promise { - return Q( - client() - .database(collection.databaseId) - .container(collection.id()) - .items.create(newDocument) - .then(response => response.resource) - ); +export function createDocument(collection: ViewModels.CollectionBase, newDocument: any): Promise { + return client() + .database(collection.databaseId) + .container(collection.id()) + .items.create(newDocument) + .then(response => response.resource); } -export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise { +export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Promise { const partitionKey = documentId.partitionKeyValue; - return Q( - client() - .database(collection.databaseId) - .container(collection.id()) - .item(documentId.id(), partitionKey) - .read() - .then(response => response.resource) - ); + return client() + .database(collection.databaseId) + .container(collection.id()) + .item(documentId.id(), partitionKey) + .read() + .then(response => response.resource); } -export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise { +export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Promise { const partitionKey = documentId.partitionKeyValue; - return Q( - client() - .database(collection.databaseId) - .container(collection.id()) - .item(documentId.id(), partitionKey) - .delete() - ); + return client() + .database(collection.databaseId) + .container(collection.id()) + .item(documentId.id(), partitionKey) + .delete(); } export function deleteConflict( collection: ViewModels.CollectionBase, conflictId: ConflictId, options: any = {} -): Q.Promise { +): Promise { options.partitionKey = options.partitionKey || getPartitionKeyHeaderForConflict(conflictId); - return Q( - client() - .database(collection.databaseId) - .container(collection.id()) - .conflict(conflictId.id()) - .delete(options) - ); + return client() + .database(collection.databaseId) + .container(collection.id()) + .conflict(conflictId.id()) + .delete(options); } -export function refreshCachedOffers(): Q.Promise { +export async function refreshCachedOffers(): Promise { if (configContext.platform === Platform.Portal) { - return sendCachedDataMessage(MessageTypes.RefreshOffers, []); - } else { - return Q(); + sendCachedDataMessage(MessageTypes.RefreshOffers, []); } } -export function refreshCachedResources(options?: any): Q.Promise { +export async function refreshCachedResources(options?: any): Promise { if (configContext.platform === Platform.Portal) { - return sendCachedDataMessage(MessageTypes.RefreshResources, []); - } else { - return Q(); + sendCachedDataMessage(MessageTypes.RefreshResources, []); } } -export function queryConflicts( +export async function queryConflicts( databaseId: string, containerId: string, query: string, options: any -): Q.Promise> { - const documentsIterator = client() +): Promise> { + return client() .database(databaseId) .container(containerId) .conflicts.query(query, options); - return Q(documentsIterator); } diff --git a/src/Common/DocumentClientUtilityBase.ts b/src/Common/DocumentClientUtilityBase.ts index d8bd683c1..1c69e224b 100644 --- a/src/Common/DocumentClientUtilityBase.ts +++ b/src/Common/DocumentClientUtilityBase.ts @@ -1,5 +1,4 @@ import { ConflictDefinition, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos"; -import Q from "q"; import * as ViewModels from "../Contracts/ViewModels"; import ConflictId from "../Explorer/Tree/ConflictId"; import DocumentId from "../Explorer/Tree/DocumentId"; @@ -16,7 +15,7 @@ export function queryDocuments( containerId: string, query: string, options: any -): Q.Promise> { +): Promise> { return DataAccessUtilityBase.queryDocuments(databaseId, containerId, query, options); } @@ -25,7 +24,7 @@ export function queryConflicts( containerId: string, query: string, options: any -): Q.Promise> { +): Promise> { return DataAccessUtilityBase.queryConflicts(databaseId, containerId, query, options); } @@ -43,17 +42,15 @@ export function executeStoredProcedure( storedProcedure: StoredProcedure, partitionKeyValue: any, params: any[] -): Q.Promise { - var deferred = Q.defer(); - +): Promise { const clearMessage = logConsoleProgress(`Executing stored procedure ${storedProcedure.id()}`); - DataAccessUtilityBase.executeStoredProcedure(collection, storedProcedure, partitionKeyValue, params) + return DataAccessUtilityBase.executeStoredProcedure(collection, storedProcedure, partitionKeyValue, params) .then( (response: any) => { - deferred.resolve(response); logConsoleInfo( `Finished executing stored procedure ${storedProcedure.id()} for container ${storedProcedure.collection.id()}` ); + return response; }, (error: any) => { handleError( @@ -61,14 +58,10 @@ export function executeStoredProcedure( `Failed to execute stored procedure ${storedProcedure.id()} for container ${storedProcedure.collection.id()}`, "ExecuteStoredProcedure" ); - deferred.reject(error); + throw error; } ) - .finally(() => { - clearMessage(); - }); - - return deferred.promise; + .finally(clearMessage); } export function queryDocumentsPage( @@ -76,150 +69,114 @@ export function queryDocumentsPage( documentsIterator: MinimalQueryIterator, firstItemIndex: number, options: any -): Q.Promise { - var deferred = Q.defer(); +): Promise { const entityName = getEntityName(); const clearMessage = logConsoleProgress(`Querying ${entityName} for container ${resourceName}`); - Q(nextPage(documentsIterator, firstItemIndex)) + return nextPage(documentsIterator, firstItemIndex) .then( (result: ViewModels.QueryResults) => { const itemCount = (result.documents && result.documents.length) || 0; logConsoleInfo(`Successfully fetched ${itemCount} ${entityName} for container ${resourceName}`); - deferred.resolve(result); + return result; }, (error: any) => { handleError(error, `Failed to query ${entityName} for container ${resourceName}`, "QueryDocumentsPage"); - deferred.reject(error); + throw error; } ) - .finally(() => { - clearMessage(); - }); - - return deferred.promise; + .finally(clearMessage); } -export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise { - var deferred = Q.defer(); +export function readDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Promise { const entityName = getEntityName(); const clearMessage = logConsoleProgress(`Reading ${entityName} ${documentId.id()}`); - DataAccessUtilityBase.readDocument(collection, documentId) - .then( - (document: any) => { - deferred.resolve(document); - }, - (error: any) => { - handleError(error, `Failed to read ${entityName} ${documentId.id()}`, "ReadDocument"); - deferred.reject(error); - } - ) - .finally(() => { - clearMessage(); - }); - - return deferred.promise; + return DataAccessUtilityBase.readDocument(collection, documentId) + .catch((error: any) => { + handleError(error, `Failed to read ${entityName} ${documentId.id()}`, "ReadDocument"); + throw error; + }) + .finally(clearMessage); } export function updateDocument( collection: ViewModels.CollectionBase, documentId: DocumentId, newDocument: any -): Q.Promise { - var deferred = Q.defer(); +): Promise { const entityName = getEntityName(); const clearMessage = logConsoleProgress(`Updating ${entityName} ${documentId.id()}`); - DataAccessUtilityBase.updateDocument(collection, documentId, newDocument) + return DataAccessUtilityBase.updateDocument(collection, documentId, newDocument) .then( (updatedDocument: any) => { logConsoleInfo(`Successfully updated ${entityName} ${documentId.id()}`); - deferred.resolve(updatedDocument); + return updatedDocument; }, (error: any) => { handleError(error, `Failed to update ${entityName} ${documentId.id()}`, "UpdateDocument"); - deferred.reject(error); + throw error; } ) - .finally(() => { - clearMessage(); - }); - - return deferred.promise; + .finally(clearMessage); } -export function createDocument(collection: ViewModels.CollectionBase, newDocument: any): Q.Promise { - var deferred = Q.defer(); +export function createDocument(collection: ViewModels.CollectionBase, newDocument: any): Promise { const entityName = getEntityName(); const clearMessage = logConsoleProgress(`Creating new ${entityName} for container ${collection.id()}`); - DataAccessUtilityBase.createDocument(collection, newDocument) + return DataAccessUtilityBase.createDocument(collection, newDocument) .then( (savedDocument: any) => { logConsoleInfo(`Successfully created new ${entityName} for container ${collection.id()}`); - deferred.resolve(savedDocument); + return savedDocument; }, (error: any) => { handleError(error, `Error while creating new ${entityName} for container ${collection.id()}`, "CreateDocument"); - deferred.reject(error); + throw error; } ) - .finally(() => { - clearMessage(); - }); - - return deferred.promise; + .finally(clearMessage); } -export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Q.Promise { - var deferred = Q.defer(); +export function deleteDocument(collection: ViewModels.CollectionBase, documentId: DocumentId): Promise { const entityName = getEntityName(); const clearMessage = logConsoleProgress(`Deleting ${entityName} ${documentId.id()}`); - DataAccessUtilityBase.deleteDocument(collection, documentId) + return DataAccessUtilityBase.deleteDocument(collection, documentId) .then( (response: any) => { logConsoleInfo(`Successfully deleted ${entityName} ${documentId.id()}`); - deferred.resolve(response); + return response; }, (error: any) => { handleError(error, `Error while deleting ${entityName} ${documentId.id()}`, "DeleteDocument"); - deferred.reject(error); + throw error; } ) - .finally(() => { - clearMessage(); - }); - - return deferred.promise; + .finally(clearMessage); } export function deleteConflict( collection: ViewModels.CollectionBase, conflictId: ConflictId, options?: any -): Q.Promise { - var deferred = Q.defer(); - +): Promise { const clearMessage = logConsoleProgress(`Deleting conflict ${conflictId.id()}`); - DataAccessUtilityBase.deleteConflict(collection, conflictId, options) + return DataAccessUtilityBase.deleteConflict(collection, conflictId, options) .then( (response: any) => { logConsoleInfo(`Successfully deleted conflict ${conflictId.id()}`); - deferred.resolve(response); + return response; }, (error: any) => { handleError(error, `Error while deleting conflict ${conflictId.id()}`, "DeleteConflict"); - deferred.reject(error); + throw error; } ) - .finally(() => { - clearMessage(); - }); - - return deferred.promise; + .finally(clearMessage); } -export function refreshCachedResources(options: any = {}): Q.Promise { +export function refreshCachedResources(options: any = {}): Promise { return DataAccessUtilityBase.refreshCachedResources(options); } -export function refreshCachedOffers(): Q.Promise { +export function refreshCachedOffers(): Promise { return DataAccessUtilityBase.refreshCachedOffers(); } diff --git a/src/Common/QueriesClient.ts b/src/Common/QueriesClient.ts index c54d167fc..d90b1bbf8 100644 --- a/src/Common/QueriesClient.ts +++ b/src/Common/QueriesClient.ts @@ -136,7 +136,7 @@ export class QueriesClient { return queryDocuments(SavedQueries.DatabaseName, SavedQueries.CollectionName, this.fetchQueriesQuery(), options) .then( (queryIterator: QueryIterator) => { - const fetchQueries = (firstItemIndex: number): Q.Promise => + const fetchQueries = (firstItemIndex: number): Promise => queryDocumentsPage(queriesCollection.id(), queryIterator, firstItemIndex, options); return QueryUtils.queryAllPages(fetchQueries).then( (results: ViewModels.QueryResults) => { diff --git a/src/Contracts/ViewModels.ts b/src/Contracts/ViewModels.ts index ea27df1f3..285d38549 100644 --- a/src/Contracts/ViewModels.ts +++ b/src/Contracts/ViewModels.ts @@ -5,7 +5,6 @@ import { TriggerDefinition, UserDefinedFunctionDefinition } from "@azure/cosmos"; -import Q from "q"; import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent"; import Explorer from "../Explorer/Explorer"; import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent"; @@ -107,7 +106,7 @@ export interface CollectionBase extends TreeNode { onDocumentDBDocumentsClick(): void; onNewQueryClick(source: any, event: MouseEvent, queryText?: string): void; - expandCollection(): Q.Promise; + expandCollection(): Promise; collapseCollection(): void; getDatabase(): Database; } @@ -172,7 +171,7 @@ export interface Collection extends CollectionBase { onDragOver(source: Collection, event: { originalEvent: DragEvent }): void; onDrop(source: Collection, event: { originalEvent: DragEvent }): void; - uploadFiles(fileList: FileList): Q.Promise; + uploadFiles(fileList: FileList): Promise; getLabel(): string; } @@ -290,7 +289,7 @@ export interface DocumentsTabOptions extends TabOptions { } export interface SettingsTabV2Options extends TabOptions { - getPendingNotification: Q.Promise; + getPendingNotification: Promise; } export interface ConflictsTabOptions extends TabOptions { diff --git a/src/Explorer/Controls/Editor/EditorComponent.ts b/src/Explorer/Controls/Editor/EditorComponent.ts index ac24189a1..bfdd2a573 100644 --- a/src/Explorer/Controls/Editor/EditorComponent.ts +++ b/src/Explorer/Controls/Editor/EditorComponent.ts @@ -57,7 +57,7 @@ class EditorViewModel extends JsonEditorViewModel { } } - protected getErrorMarkers(input: string): Q.Promise { + protected async getErrorMarkers(input: string): Promise { return ErrorMarkProvider.getErrorMark(input); } } diff --git a/src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts b/src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts index 459f3b884..5b4879705 100644 --- a/src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts +++ b/src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts @@ -1,4 +1,3 @@ -import Q from "q"; import * as monaco from "monaco-editor"; import * as ViewModels from "../../../Contracts/ViewModels"; import { WaitsForTemplateViewModel } from "../../WaitsForTemplateViewModel"; @@ -107,8 +106,8 @@ export class JsonEditorViewModel extends WaitsForTemplateViewModel { protected registerCompletionItemProvider() {} // Interface. Will be implemented in children editor view model such as EditorViewModel. - protected getErrorMarkers(input: string): Q.Promise { - return Q.Promise(() => {}); + protected getErrorMarkers(input: string): Promise { + return new Promise(() => {}); } protected getEditorLanguage(): string { diff --git a/src/Explorer/Controls/Settings/SettingsComponent.test.tsx b/src/Explorer/Controls/Settings/SettingsComponent.test.tsx index 9d862864c..61a65a006 100644 --- a/src/Explorer/Controls/Settings/SettingsComponent.test.tsx +++ b/src/Explorer/Controls/Settings/SettingsComponent.test.tsx @@ -31,7 +31,6 @@ jest.mock("../../../Common/dataAccess/updateCollection", () => ({ })); import { updateOffer } from "../../../Common/dataAccess/updateOffer"; import { MongoDBCollectionResource } from "../../../Utils/arm/generatedClients/2020-04-01/types"; -import Q from "q"; jest.mock("../../../Common/dataAccess/updateOffer", () => ({ updateOffer: jest.fn().mockReturnValue({} as DataModels.Offer) })); @@ -47,9 +46,7 @@ describe("SettingsComponent", () => { hashLocation: "settings", isActive: ko.observable(false), onUpdateTabsButtons: undefined, - getPendingNotification: Q.Promise(() => { - return; - }) + getPendingNotification: Promise.resolve(undefined) }) }; diff --git a/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts b/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts index 3bc972832..f85a2ade1 100644 --- a/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts +++ b/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts @@ -3,7 +3,6 @@ jest.mock("../Graph/GraphExplorerComponent/GremlinClient"); jest.mock("../../Common/dataAccess/createCollection"); import * as ko from "knockout"; import * as ViewModels from "../../Contracts/ViewModels"; -import Q from "q"; import { ContainerSampleGenerator } from "./ContainerSampleGenerator"; import { createDocument } from "../../Common/DocumentClientUtilityBase"; import Explorer from "../Explorer"; @@ -21,7 +20,7 @@ describe("ContainerSampleGenerator", () => { explorerStub.canExceedMaximumValue = ko.computed(() => false); explorerStub.hasAutoPilotV2FeatureFlag = ko.computed(() => true); explorerStub.findDatabaseWithId = () => database; - explorerStub.refreshAllDatabases = () => Q.resolve(); + explorerStub.refreshAllDatabases = () => Promise.resolve(); return explorerStub; }; diff --git a/src/Explorer/DataSamples/ContainerSampleGenerator.ts b/src/Explorer/DataSamples/ContainerSampleGenerator.ts index 3c3b28732..154c9f200 100644 --- a/src/Explorer/DataSamples/ContainerSampleGenerator.ts +++ b/src/Explorer/DataSamples/ContainerSampleGenerator.ts @@ -70,7 +70,7 @@ export class ContainerSampleGenerator { if (!collection) { throw new Error("No container to populate"); } - const promises: Q.Promise[] = []; + const promises: Promise[] = []; if (this.container.isPreferredApiGraph()) { // For Gremlin, all queries are executed sequentially, because some queries might be dependent on other queries diff --git a/src/Explorer/Explorer.ts b/src/Explorer/Explorer.ts index 7e6501afb..3e5abc105 100644 --- a/src/Explorer/Explorer.ts +++ b/src/Explorer/Explorer.ts @@ -217,7 +217,7 @@ export default class Explorer { public shouldShowShareDialogContents: ko.Observable; public shareAccessData: ko.Observable; - public renewExplorerShareAccess: (explorer: Explorer, token: string) => Q.Promise; + public renewExplorerShareAccess: (explorer: Explorer, token: string) => Promise; public renewTokenError: ko.Observable; public tokenForRenewal: ko.Observable; public shareAccessToggleState: ko.Observable; @@ -1120,7 +1120,7 @@ export default class Explorer { "Initiating connection to account" ); this.renewExplorerShareAccess(this, this.tokenForRenewal()) - .fail((error: any) => { + .catch((error: any) => { const stringifiedError: string = error.message; this.renewTokenError("Invalid connection string specified"); NotificationConsoleUtils.logConsoleMessage( @@ -1157,33 +1157,27 @@ export default class Explorer { ); } - public renewShareAccess(token: string): Q.Promise { + public async renewShareAccess(token: string): Promise { if (!this.renewExplorerShareAccess) { - return Q.reject("Not implemented"); + throw "Not implemented"; } - const deferred: Q.Deferred = Q.defer(); const id: string = NotificationConsoleUtils.logConsoleMessage( ConsoleDataType.InProgress, "Initiating connection to account" ); - this.renewExplorerShareAccess(this, token) + return this.renewExplorerShareAccess(this, token) .then( () => { NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Info, "Connection successful"); this.renewAdHocAccessPane && this.renewAdHocAccessPane.close(); - deferred.resolve(); }, (error: any) => { NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Error, `Failed to connect: ${error.message}`); - deferred.reject(error); + throw error; } ) - .finally(() => { - NotificationConsoleUtils.clearInProgressMessageWithId(id); - }); - - return deferred.promise; + .finally(() => NotificationConsoleUtils.clearInProgressMessageWithId(id)); } public displayGuestAccessTokenRenewalPrompt(): void { @@ -1378,24 +1372,19 @@ export default class Explorer { } } - public refreshDatabaseForResourceToken(): Q.Promise { + public async refreshDatabaseForResourceToken(): Promise { const databaseId = this.resourceTokenDatabaseId(); const collectionId = this.resourceTokenCollectionId(); if (!databaseId || !collectionId) { - return Q.reject(); + throw new Error(); } - const deferred: Q.Deferred = Q.defer(); - readCollection(databaseId, collectionId).then((collection: DataModels.Collection) => { - this.resourceTokenCollection(new ResourceTokenCollection(this, databaseId, collection)); - this.selectedNode(this.resourceTokenCollection()); - deferred.resolve(); - }); - - return deferred.promise; + const collection = await readCollection(databaseId, collectionId); + this.resourceTokenCollection(new ResourceTokenCollection(this, databaseId, collection)); + this.selectedNode(this.resourceTokenCollection()); } - public refreshAllDatabases(isInitialLoad?: boolean): Q.Promise { + public refreshAllDatabases(isInitialLoad?: boolean): Promise { this.isRefreshingExplorer(true); const startKey: number = TelemetryProcessor.traceStart(Action.LoadDatabases, { databaseAccountName: this.databaseAccount() && this.databaseAccount().name, @@ -1412,89 +1401,85 @@ export default class Explorer { } // TODO: Refactor - const deferred: Q.Deferred = Q.defer(); this._setLoadingStatusText("Fetching databases..."); - readDatabases().then( - (databases: DataModels.Database[]) => { - this._setLoadingStatusText("Successfully fetched databases."); - TelemetryProcessor.traceSuccess( - Action.LoadDatabases, - { - databaseAccountName: this.databaseAccount().name, - defaultExperience: this.defaultExperience(), - dataExplorerArea: Constants.Areas.ResourceTree - }, - startKey - ); - const currentlySelectedNode: ViewModels.TreeNode = this.selectedNode(); - const deltaDatabases = this.getDeltaDatabases(databases); - this.addDatabasesToList(deltaDatabases.toAdd); - this.deleteDatabasesFromList(deltaDatabases.toDelete); - this.selectedNode(currentlySelectedNode); - this._setLoadingStatusText("Fetching containers..."); - this.refreshAndExpandNewDatabases(deltaDatabases.toAdd) - .then( - () => { - this._setLoadingStatusText("Successfully fetched containers."); - deferred.resolve(); - }, - reason => { - this._setLoadingStatusText("Failed to fetch containers."); - deferred.reject(reason); - } - ) - .finally(() => this.isRefreshingExplorer(false)); - }, - error => { - this._setLoadingStatusText("Failed to fetch databases."); - this.isRefreshingExplorer(false); - deferred.reject(error); - TelemetryProcessor.traceFailure( - Action.LoadDatabases, - { - databaseAccountName: this.databaseAccount().name, - defaultExperience: this.defaultExperience(), - dataExplorerArea: Constants.Areas.ResourceTree, - error: error.message - }, - startKey - ); - NotificationConsoleUtils.logConsoleMessage( - ConsoleDataType.Error, - `Error while refreshing databases: ${error.message}` - ); - } - ); - - return deferred.promise.then( - () => { - if (resourceTreeStartKey != null) { + return readDatabases() + .then( + (databases: DataModels.Database[]) => { + this._setLoadingStatusText("Successfully fetched databases."); TelemetryProcessor.traceSuccess( - Action.LoadResourceTree, + Action.LoadDatabases, { - databaseAccountName: this.databaseAccount() && this.databaseAccount().name, - defaultExperience: this.defaultExperience && this.defaultExperience(), + databaseAccountName: this.databaseAccount().name, + defaultExperience: this.defaultExperience(), dataExplorerArea: Constants.Areas.ResourceTree }, - resourceTreeStartKey + startKey ); - } - }, - reason => { - if (resourceTreeStartKey != null) { + const currentlySelectedNode: ViewModels.TreeNode = this.selectedNode(); + const deltaDatabases = this.getDeltaDatabases(databases); + this.addDatabasesToList(deltaDatabases.toAdd); + this.deleteDatabasesFromList(deltaDatabases.toDelete); + this.selectedNode(currentlySelectedNode); + this._setLoadingStatusText("Fetching containers..."); + this.refreshAndExpandNewDatabases(deltaDatabases.toAdd) + .then( + () => this._setLoadingStatusText("Successfully fetched containers."), + reason => { + this._setLoadingStatusText("Failed to fetch containers."); + throw reason; + } + ) + .finally(() => this.isRefreshingExplorer(false)); + }, + error => { + this._setLoadingStatusText("Failed to fetch databases."); + this.isRefreshingExplorer(false); TelemetryProcessor.traceFailure( - Action.LoadResourceTree, + Action.LoadDatabases, { - databaseAccountName: this.databaseAccount() && this.databaseAccount().name, - defaultExperience: this.defaultExperience && this.defaultExperience(), + databaseAccountName: this.databaseAccount().name, + defaultExperience: this.defaultExperience(), dataExplorerArea: Constants.Areas.ResourceTree, - error: reason + error: error.message }, - resourceTreeStartKey + startKey ); + NotificationConsoleUtils.logConsoleMessage( + ConsoleDataType.Error, + `Error while refreshing databases: ${error.message}` + ); + throw error; } - } - ); + ) + .then( + () => { + if (resourceTreeStartKey != null) { + TelemetryProcessor.traceSuccess( + Action.LoadResourceTree, + { + databaseAccountName: this.databaseAccount() && this.databaseAccount().name, + defaultExperience: this.defaultExperience && this.defaultExperience(), + dataExplorerArea: Constants.Areas.ResourceTree + }, + resourceTreeStartKey + ); + } + }, + reason => { + if (resourceTreeStartKey != null) { + TelemetryProcessor.traceFailure( + Action.LoadResourceTree, + { + databaseAccountName: this.databaseAccount() && this.databaseAccount().name, + defaultExperience: this.defaultExperience && this.defaultExperience(), + dataExplorerArea: Constants.Areas.ResourceTree, + error: reason + }, + resourceTreeStartKey + ); + } + } + ); } public onRefreshDatabasesKeyPress = (source: any, event: KeyboardEvent): boolean => { @@ -1794,7 +1779,7 @@ export default class Explorer { inputs.extensionEndpoint = configContext.PROXY_PATH; } - const initPromise: Q.Promise = inputs ? this.initDataExplorerWithFrameInputs(inputs) : Q(); + const initPromise: Promise = inputs ? this.initDataExplorerWithFrameInputs(inputs) : Promise.resolve(); initPromise.then(() => { const openAction: ActionContracts.DataExplorerAction = message.openAction; @@ -1888,7 +1873,7 @@ export default class Explorer { return false; } - public initDataExplorerWithFrameInputs(inputs: ViewModels.DataExplorerInputsFrame): Q.Promise { + public async initDataExplorerWithFrameInputs(inputs: ViewModels.DataExplorerInputsFrame): Promise { if (inputs != null) { const authorizationToken = inputs.authorizationToken || ""; const masterKey = inputs.masterKey || ""; @@ -1938,7 +1923,6 @@ export default class Explorer { this.isAccountReady(true); } - return Q(); } public setFeatureFlagsFromFlights(flights: readonly string[]): void { @@ -2056,7 +2040,7 @@ export default class Explorer { // we reload collections for all databases so the resource tree reflects any collection-level changes // i.e addition of stored procedures, etc. const deferred: Q.Deferred = Q.defer(); - let loadCollectionPromises: Q.Promise[] = []; + let loadCollectionPromises: Promise[] = []; // If the user has a lot of databases, only load expanded databases. const databasesToLoad = @@ -2440,7 +2424,7 @@ export default class Explorer { return true; } - public renameNotebook(notebookFile: NotebookContentItem): Q.Promise { + public async renameNotebook(notebookFile: NotebookContentItem): Promise { if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) { const error = "Attempt to rename notebook, but notebook is not enabled"; Logger.logError(error, "Explorer/renameNotebook"); @@ -2457,39 +2441,35 @@ export default class Explorer { ); if (openedNotebookTabs.length > 0) { this.showOkModalDialog("Unable to rename file", "This file is being edited. Please close the tab and try again."); - return Q.reject(); + throw new Error(); } const originalPath = notebookFile.path; - const result = this.stringInputPane - .openWithOptions({ - errorMessage: "Could not rename notebook", - inProgressMessage: "Renaming notebook to", - successMessage: "Renamed notebook to", - inputLabel: "Enter new notebook name", - paneTitle: "Rename Notebook", - submitButtonLabel: "Rename", - defaultInput: FileSystemUtil.stripExtension(notebookFile.name, "ipynb"), - onSubmit: (input: string) => this.notebookManager?.notebookContentClient.renameNotebook(notebookFile, input) - }) - .then(newNotebookFile => { - const notebookTabs = this.tabsManager.getTabs( - ViewModels.CollectionTabKind.NotebookV2, - (tab: NotebookV2Tab) => tab.notebookPath && FileSystemUtil.isPathEqual(tab.notebookPath(), originalPath) - ); - notebookTabs.forEach(tab => { - tab.tabTitle(newNotebookFile.name); - tab.tabPath(newNotebookFile.path); - (tab as NotebookV2Tab).notebookPath(newNotebookFile.path); - }); + const newNotebookFile = await this.stringInputPane.openWithOptions({ + errorMessage: "Could not rename notebook", + inProgressMessage: "Renaming notebook to", + successMessage: "Renamed notebook to", + inputLabel: "Enter new notebook name", + paneTitle: "Rename Notebook", + submitButtonLabel: "Rename", + defaultInput: FileSystemUtil.stripExtension(notebookFile.name, "ipynb"), + onSubmit: (input: string) => this.notebookManager?.notebookContentClient.renameNotebook(notebookFile, input) + }); + const notebookTabs = this.tabsManager.getTabs( + ViewModels.CollectionTabKind.NotebookV2, + (tab: NotebookV2Tab) => tab.notebookPath && FileSystemUtil.isPathEqual(tab.notebookPath(), originalPath) + ); + notebookTabs.forEach(tab => { + tab.tabTitle(newNotebookFile.name); + tab.tabPath(newNotebookFile.path); + (tab as NotebookV2Tab).notebookPath(newNotebookFile.path); + }); - return newNotebookFile; - }); - result.then(() => this.resourceTree.triggerRender()); - return result; + this.resourceTree.triggerRender(); + return newNotebookFile; } - public onCreateDirectory(parent: NotebookContentItem): Q.Promise { + public async onCreateDirectory(parent: NotebookContentItem): Promise { if (!this.isNotebookEnabled() || !this.notebookManager?.notebookContentClient) { const error = "Attempt to create notebook directory, but notebook is not enabled"; Logger.logError(error, "Explorer/onCreateDirectory"); @@ -2497,7 +2477,7 @@ export default class Explorer { throw new Error(error); } - const result = this.stringInputPane.openWithOptions({ + const result = await this.stringInputPane.openWithOptions({ errorMessage: "Could not create directory ", inProgressMessage: "Creating directory ", successMessage: "Created directory ", @@ -2507,7 +2487,7 @@ export default class Explorer { defaultInput: "", onSubmit: (input: string) => this.notebookManager?.notebookContentClient.createDirectory(parent, input) }); - result.then(() => this.resourceTree.triggerRender()); + this.resourceTree.triggerRender(); return result; } diff --git a/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts b/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts index 6504e7794..69af08a55 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts +++ b/src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts @@ -378,8 +378,7 @@ export class D3ForceGraph implements GraphRenderer { * @param targetPosition * @return promise with shift offset */ - private shiftGraph(targetPosition: Point2D): Q.Promise { - const deferred: Q.Deferred = Q.defer(); + private async shiftGraph(targetPosition: Point2D): Promise { const offset = { x: this.width / 2 - targetPosition.x, y: this.height / 2 - targetPosition.y }; this.viewCenter = targetPosition; @@ -391,18 +390,15 @@ export class D3ForceGraph implements GraphRenderer { .translate(-targetPosition.x, -targetPosition.y); }; - this.zoomBackground + const transition = this.zoomBackground .transition() .duration(D3ForceGraph.TRANSITION_STEP1_MS) - .call(this.zoom.transform, transform) - .on("end", () => { - deferred.resolve(offset); - }); - } else { - deferred.resolve(null); - } + .call(this.zoom.transform, transform); - return deferred.promise; + await new Promise(resolve => transition.on("end", resolve)); + return offset; + } + return null; } private onGraphDataUpdate(graph: GraphData) { @@ -435,7 +431,7 @@ export class D3ForceGraph implements GraphRenderer { } } - private animateRemoveExitSelections(): Q.Promise { + private animateRemoveExitSelections(): Promise { const deferred1 = Q.defer(); const deferred2 = Q.defer(); const linkExitSelection = this.linkSelection.exit(); @@ -508,7 +504,7 @@ export class D3ForceGraph implements GraphRenderer { deferred2.resolve(); } - return Q.allSettled([deferred1.promise, deferred2.promise]).then(undefined); + return Promise.all([deferred1.promise, deferred2.promise]).then(undefined); } /** diff --git a/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.test.tsx b/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.test.tsx index dd3e93359..310df343d 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.test.tsx +++ b/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.test.tsx @@ -1,6 +1,5 @@ import React from "react"; import { mount, ReactWrapper } from "enzyme"; -import * as Q from "q"; import { NodePropertiesComponent, NodePropertiesComponentProps, Mode } from "./NodePropertiesComponent"; import { GraphHighlightedNodeData, EditedProperties, EditedEdges, PossibleVertex } from "./GraphExplorer"; @@ -41,11 +40,11 @@ describe("Property pane", () => { node: highlightedNode, getPkIdFromNodeData: (v: GraphHighlightedNodeData): string => null, collectionPartitionKeyProperty: null, - updateVertexProperties: (editedProperties: EditedProperties): Q.Promise => Q.resolve(), + updateVertexProperties: (editedProperties: EditedProperties): Promise => Promise.resolve(), selectNode: (id: string): void => {}, - updatePossibleVertices: (): Q.Promise => Q.resolve(null), + updatePossibleVertices: async (): Promise => null, possibleEdgeLabels: null, - editGraphEdges: (editedEdges: EditedEdges): Q.Promise => Q.resolve(), + editGraphEdges: async (editedEdges: EditedEdges): Promise => undefined, deleteHighlightedNode: (): void => {}, onModeChanged: (newMode: Mode): void => {}, viewMode: Mode.READONLY_PROP diff --git a/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx b/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx index cc01e0a8a..c5c361998 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx +++ b/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx @@ -36,11 +36,11 @@ export interface NodePropertiesComponentProps { node: GraphHighlightedNodeData; getPkIdFromNodeData: (v: GraphHighlightedNodeData) => string; collectionPartitionKeyProperty: string; - updateVertexProperties: (editedProperties: EditedProperties) => Q.Promise; + updateVertexProperties: (editedProperties: EditedProperties) => Promise; selectNode: (id: string) => void; - updatePossibleVertices: () => Q.Promise; + updatePossibleVertices: () => Promise; possibleEdgeLabels: Item[]; - editGraphEdges: (editedEdges: EditedEdges) => Q.Promise; + editGraphEdges: (editedEdges: EditedEdges) => Promise; deleteHighlightedNode: () => void; onModeChanged: (newMode: Mode) => void; viewMode: Mode; // If viewMode is specified in parent, keep state in sync with it diff --git a/src/Explorer/Panes/CassandraAddCollectionPane.ts b/src/Explorer/Panes/CassandraAddCollectionPane.ts index 4756d14b4..b743fac7c 100644 --- a/src/Explorer/Panes/CassandraAddCollectionPane.ts +++ b/src/Explorer/Panes/CassandraAddCollectionPane.ts @@ -350,7 +350,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase { } this.isExecuting(true); const autoPilotCommand = `cosmosdb_autoscale_max_throughput`; - let createTableAndKeyspacePromise: Q.Promise; + let createTableAndKeyspacePromise: Promise; const toCreateKeyspace: boolean = this.keyspaceCreateNew(); const useAutoPilotForKeyspace: boolean = (!this.hasAutoPilotV2FeatureFlag() && this.isSharedAutoPilotSelected() && !!this.sharedAutoPilotThroughput()) || diff --git a/src/Explorer/Panes/DeleteCollectionConfirmationPane.test.ts b/src/Explorer/Panes/DeleteCollectionConfirmationPane.test.ts index 4b9e9f257..8331eb235 100644 --- a/src/Explorer/Panes/DeleteCollectionConfirmationPane.test.ts +++ b/src/Explorer/Panes/DeleteCollectionConfirmationPane.test.ts @@ -1,7 +1,6 @@ jest.mock("../../Common/dataAccess/deleteCollection"); import * as ko from "knockout"; import * as sinon from "sinon"; -import Q from "q"; import * as DataModels from "../../Contracts/DataModels"; import * as ViewModels from "../../Contracts/ViewModels"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; @@ -58,7 +57,7 @@ describe("Delete Collection Confirmation Pane", () => { it("should return true if last collection and database does not have shared throughput else false", () => { let fakeExplorer = new Explorer(); fakeExplorer.isNotificationConsoleExpanded = ko.observable(false); - fakeExplorer.refreshAllDatabases = () => Q.resolve(); + fakeExplorer.refreshAllDatabases = () => Promise.resolve(); let pane = new DeleteCollectionConfirmationPane({ id: "deletecollectionconfirmationpane", @@ -119,7 +118,7 @@ describe("Delete Collection Confirmation Pane", () => { fakeExplorer.selectedNode = ko.observable(); fakeExplorer.isLastCollection = () => true; fakeExplorer.isSelectedDatabaseShared = () => false; - fakeExplorer.refreshAllDatabases = () => Q.resolve(); + fakeExplorer.refreshAllDatabases = () => Promise.resolve(); let pane = new DeleteCollectionConfirmationPane({ id: "deletecollectionconfirmationpane", diff --git a/src/Explorer/Panes/DeleteCollectionConfirmationPane.ts b/src/Explorer/Panes/DeleteCollectionConfirmationPane.ts index 5af4cd9d4..c79087d17 100644 --- a/src/Explorer/Panes/DeleteCollectionConfirmationPane.ts +++ b/src/Explorer/Panes/DeleteCollectionConfirmationPane.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import Q from "q"; import * as ViewModels from "../../Contracts/ViewModels"; import * as Constants from "../../Common/Constants"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; diff --git a/src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts b/src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts index a150a1a6d..409d38955 100644 --- a/src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts +++ b/src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts @@ -1,7 +1,6 @@ jest.mock("../../Common/dataAccess/deleteDatabase"); jest.mock("../../Shared/Telemetry/TelemetryProcessor"); import * as ko from "knockout"; -import Q from "q"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; import * as DataModels from "../../Contracts/DataModels"; import * as ViewModels from "../../Contracts/ViewModels"; @@ -91,7 +90,7 @@ describe("Delete Database Confirmation Pane", () => { collections: ko.observableArray() } as ViewModels.Database; }; - fakeExplorer.refreshAllDatabases = () => Q.resolve(); + fakeExplorer.refreshAllDatabases = () => Promise.resolve(); fakeExplorer.isNotificationConsoleExpanded = ko.observable(false); fakeExplorer.selectedDatabaseId = ko.computed(() => selectedDatabaseId); fakeExplorer.isSelectedDatabaseShared = () => false; diff --git a/src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts b/src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts index 980d41ee8..d1af84801 100644 --- a/src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts +++ b/src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import Q from "q"; import * as Constants from "../../Common/Constants"; import * as ViewModels from "../../Contracts/ViewModels"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; @@ -31,7 +30,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase { this.resetData(); } - public submit(): Q.Promise { + public async submit(): Promise { if (!this._isValid()) { const selectedDatabase: ViewModels.Database = this.container.findSelectedDatabase(); this.formErrors("Input database name does not match the selected database"); @@ -39,7 +38,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase { ConsoleDataType.Error, `Error while deleting collection ${selectedDatabase && selectedDatabase.id()}: ${this.formErrors()}` ); - return Q.resolve(); + return; } this.formErrors(""); @@ -53,7 +52,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase { paneTitle: this.title() }); // TODO: Should not be a Q promise anymore, but the Cassandra code requires it - let promise: Q.Promise; + let promise: Promise; if (this.container.isPreferredApiCassandra()) { promise = (this.container.tableDataClient).deleteTableOrKeyspace( this.container.databaseAccount().properties.cassandraEndpoint, @@ -62,7 +61,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase { this.container ); } else { - promise = Q(deleteDatabase(selectedDatabase.id())); + promise = deleteDatabase(selectedDatabase.id()); } return promise.then( () => { diff --git a/src/Explorer/Panes/LoadQueryPane.ts b/src/Explorer/Panes/LoadQueryPane.ts index 8ac434edd..3231e23d3 100644 --- a/src/Explorer/Panes/LoadQueryPane.ts +++ b/src/Explorer/Panes/LoadQueryPane.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import * as Q from "q"; import * as Constants from "../../Common/Constants"; import * as ViewModels from "../../Contracts/ViewModels"; import { ContextualPaneBase } from "./ContextualPaneBase"; @@ -97,33 +96,30 @@ export class LoadQueryPane extends ContextualPaneBase { return true; }; - public loadQueryFromFile(file: File): Q.Promise { + public async loadQueryFromFile(file: File): Promise { const selectedCollection: ViewModels.Collection = this.container && this.container.findSelectedCollection(); if (!selectedCollection) { // should never get into this state Logger.logError("No collection was selected", "LoadQueryPane.loadQueryFromFile"); - return Q.reject("No collection was selected"); + throw new Error("No collection was selected"); } else if (this.container.isPreferredApiMongoDB()) { selectedCollection.onNewMongoQueryClick(selectedCollection, null); } else { selectedCollection.onNewQueryClick(selectedCollection, null); } - const deferred: Q.Deferred = Q.defer(); const reader = new FileReader(); reader.onload = (evt: any): void => { const fileData: string = evt.target.result; const queryTab = this.container.tabsManager.activeTab() as QueryTab; queryTab.initialEditorContent(fileData); queryTab.sqlQueryEditorContent(fileData); - deferred.resolve(); }; reader.onerror = (evt: ProgressEvent): void => { - deferred.reject((evt as any).error.message); + throw new Error((evt as any).error.message); }; reader.readAsText(file); - return deferred.promise; } private updateSelectedFilesTitle(fileList: FileList) { diff --git a/src/Explorer/Tables/DataTable/DataTableOperations.ts b/src/Explorer/Tables/DataTable/DataTableOperations.ts index ef2033db8..3965ad08f 100644 --- a/src/Explorer/Tables/DataTable/DataTableOperations.ts +++ b/src/Explorer/Tables/DataTable/DataTableOperations.ts @@ -1,5 +1,4 @@ import _ from "underscore"; -import Q from "q"; import * as Entities from "../Entities"; import * as QueryBuilderConstants from "../Constants"; @@ -84,11 +83,11 @@ export function filterColumns(table: DataTables.DataTable, settings: boolean[]): * Reorder columns based on current order. * If no current order is specified, reorder the columns based on intial order. */ -export function reorderColumns( +export async function reorderColumns( table: DataTables.DataTable, targetOrder: number[], currentOrder?: number[] -): Q.Promise { +): Promise { var columnsCount: number = targetOrder.length; var isCurrentOrderPassedIn: boolean = !!currentOrder; if (!isCurrentOrderPassedIn) { @@ -107,13 +106,9 @@ export function reorderColumns( var transformationOrder: number[] = isCurrentOrderPassedIn ? calculateTransformationOrder(currentOrder, targetOrder) : targetOrder; - try { - $.fn.dataTable.ColReorder(table).fnOrder(transformationOrder); - } catch (err) { - return Q.reject(err); - } + $.fn.dataTable.ColReorder(table).fnOrder(transformationOrder); } - return Q.resolve(null); + return null; } export function resetColumns(table: DataTables.DataTable): void { diff --git a/src/Explorer/Tables/DataTable/TableCommands.ts b/src/Explorer/Tables/DataTable/TableCommands.ts index 70226fc62..b14b09677 100644 --- a/src/Explorer/Tables/DataTable/TableCommands.ts +++ b/src/Explorer/Tables/DataTable/TableCommands.ts @@ -1,5 +1,4 @@ import _ from "underscore"; -import Q from "q"; import * as DataTableUtilities from "./DataTableUtilities"; import * as DataTableOperations from "./DataTableOperations"; import TableEntityListViewModel from "./TableEntityListViewModel"; @@ -49,7 +48,7 @@ export default class TableCommands { /** * Edit entity */ - public editEntityCommand(viewModel: TableEntityListViewModel): Q.Promise { + public editEntityCommand(viewModel: TableEntityListViewModel): Promise { if (!viewModel) { return null; // Error } @@ -68,7 +67,7 @@ export default class TableCommands { return null; } - public deleteEntitiesCommand(viewModel: TableEntityListViewModel): Q.Promise { + public deleteEntitiesCommand(viewModel: TableEntityListViewModel): Promise { if (!viewModel) { return null; // Error } @@ -92,7 +91,7 @@ export default class TableCommands { return null; } - public customizeColumnsCommand(viewModel: TableEntityListViewModel): Q.Promise { + public customizeColumnsCommand(viewModel: TableEntityListViewModel): Promise { var table: DataTables.DataTable = viewModel.table; var displayedColumnNames: string[] = DataTableOperations.getDataTableHeaders(table); var columnsCount: number = displayedColumnNames.length; @@ -120,7 +119,7 @@ export default class TableCommands { return null; } - public reorderColumnsBasedOnSelectedEntities(viewModel: TableEntityListViewModel): Q.Promise { + public reorderColumnsBasedOnSelectedEntities(viewModel: TableEntityListViewModel): Promise { var selected = viewModel.selected(); if (!selected || !selected.length) { return null; diff --git a/src/Explorer/Tables/Utilities.ts b/src/Explorer/Tables/Utilities.ts index 3a851dfc8..f3b9cfd31 100644 --- a/src/Explorer/Tables/Utilities.ts +++ b/src/Explorer/Tables/Utilities.ts @@ -1,5 +1,4 @@ import * as _ from "underscore"; -import Q from "q"; import * as Entities from "./Entities"; import { CassandraTableKey } from "./TableDataClient"; import * as Constants from "./Constants"; @@ -19,8 +18,8 @@ export function guid() { /** * Returns a promise that resolves in the specified number of milliseconds. */ -export function delay(milliseconds: number): Q.Promise { - return Q.delay(milliseconds); +export function delay(milliseconds: number): Promise { + return new Promise(resolve => setTimeout(resolve, milliseconds)); } /** diff --git a/src/Explorer/Tabs/ConflictsTab.ts b/src/Explorer/Tabs/ConflictsTab.ts index a5c188805..2e7a194b3 100644 --- a/src/Explorer/Tabs/ConflictsTab.ts +++ b/src/Explorer/Tabs/ConflictsTab.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import Q from "q"; import * as Constants from "../../Common/Constants"; import * as DataModels from "../../Contracts/DataModels"; import * as ViewModels from "../../Contracts/ViewModels"; @@ -225,7 +224,7 @@ export default class ConflictsTab extends TabsBase { }); } - public refreshDocumentsGrid(): Q.Promise { + public refreshDocumentsGrid(): Promise { // clear documents grid this.conflictIds([]); return this.createIterator() @@ -256,19 +255,17 @@ export default class ConflictsTab extends TabsBase { return true; }; - public onConflictIdClick(clickedDocumentId: ConflictId): Q.Promise { + public async onConflictIdClick(clickedDocumentId: ConflictId): Promise { if (this.editorState() !== ViewModels.DocumentExplorerState.noDocumentSelected) { - return Q(); + return; } this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); - - return Q(); } - public onAcceptChangesClick = (): Q.Promise => { + public onAcceptChangesClick = async (): Promise => { if (this.isEditorDirty() && !this._isIgnoreDirtyEditor()) { - return Q(); + return; } this.isExecutionError(false); @@ -286,7 +283,7 @@ export default class ConflictsTab extends TabsBase { conflictResourceId: selectedConflict.resourceId }); - let operationPromise: Q.Promise = Q(); + let operationPromise: Promise; if (selectedConflict.operationType === Constants.ConflictOperationType.Replace) { const documentContent = JSON.parse(this.selectedConflictContent()); @@ -358,7 +355,7 @@ export default class ConflictsTab extends TabsBase { .finally(() => this.isExecuting(false)); }; - public onDeleteClick = (): Q.Promise => { + public onDeleteClick = (): Promise => { this.isExecutionError(false); this.isExecuting(true); @@ -418,40 +415,34 @@ export default class ConflictsTab extends TabsBase { .finally(() => this.isExecuting(false)); }; - public onDiscardClick = (): Q.Promise => { + public onDiscardClick = async (): Promise => { this.selectedConflictContent(this.selectedConflictContent.getEditableOriginalValue()); this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); - - return Q(); }; - public onValidDocumentEdit(): Q.Promise { + public async onValidDocumentEdit(): Promise { this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentDirtyValid); - return Q(); } - public onInvalidDocumentEdit(): Q.Promise { + public async onInvalidDocumentEdit(): Promise { if ( this.editorState() === ViewModels.DocumentExplorerState.exisitingDocumentNoEdits || this.editorState() === ViewModels.DocumentExplorerState.exisitingDocumentDirtyValid ) { this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentDirtyInvalid); - return Q(); } - - return Q(); } - public onTabClick(): Q.Promise { + public onTabClick(): Promise { return super.onTabClick().then(() => { this.collection && this.collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Conflicts); }); } - public onActivate(): Q.Promise { + public onActivate(): Promise { return super.onActivate().then(() => { if (this._documentsIterator) { - return Q.resolve(this._documentsIterator); + return this._documentsIterator; } return this.createIterator().then( @@ -481,7 +472,7 @@ export default class ConflictsTab extends TabsBase { }); } - public onRefreshClick(): Q.Promise { + public onRefreshClick(): Promise { return this.refreshDocumentsGrid().then(() => { this.selectedConflictContent(""); this.selectedConflictId(null); @@ -489,7 +480,7 @@ export default class ConflictsTab extends TabsBase { }); } - public createIterator(): Q.Promise> { + public createIterator(): Promise> { // TODO: Conflict Feed does not allow filtering atm const query: string = undefined; let options: any = {}; @@ -497,7 +488,7 @@ export default class ConflictsTab extends TabsBase { return queryConflicts(this.collection.databaseId, this.collection.id(), query, options); } - public loadNextPage(): Q.Promise { + public loadNextPage(): Promise { this.isExecuting(true); this.isExecutionError(false); return this._loadNextPageInternal() @@ -564,8 +555,8 @@ export default class ConflictsTab extends TabsBase { } }; - protected _loadNextPageInternal(): Q.Promise { - return Q(this._documentsIterator.fetchNext().then(response => response.resources)); + protected _loadNextPageInternal(): Promise { + return this._documentsIterator.fetchNext().then(response => response.resources); } protected _onEditorContentChange(newContent: string) { @@ -577,22 +568,20 @@ export default class ConflictsTab extends TabsBase { } } - public initDocumentEditorForCreate(documentId: ConflictId, documentToInsert: any): Q.Promise { + public async initDocumentEditorForCreate(documentId: ConflictId, documentToInsert: any): Promise { if (documentId) { let parsedConflictContent: any = JSON.parse(documentToInsert); const renderedConflictContent: string = this.renderObjectForEditor(parsedConflictContent, null, 4); this.selectedConflictContent.setBaseline(renderedConflictContent); this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); } - - return Q(); } - public initDocumentEditorForReplace( + public async initDocumentEditorForReplace( documentId: ConflictId, conflictContent: any, currentContent: any - ): Q.Promise { + ): Promise { if (documentId) { currentContent = ConflictsTab.removeSystemProperties(currentContent); const renderedCurrentContent: string = this.renderObjectForEditor(currentContent, null, 4); @@ -605,11 +594,9 @@ export default class ConflictsTab extends TabsBase { this.selectedConflictContent.setBaseline(renderedConflictContent); this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); } - - return Q(); } - public initDocumentEditorForDelete(documentId: ConflictId, documentToDelete: any): Q.Promise { + public async initDocumentEditorForDelete(documentId: ConflictId, documentToDelete: any): Promise { if (documentId) { let parsedDocumentToDelete: any = JSON.parse(documentToDelete); parsedDocumentToDelete = ConflictsTab.removeSystemProperties(parsedDocumentToDelete); @@ -617,15 +604,12 @@ export default class ConflictsTab extends TabsBase { this.selectedConflictContent.setBaseline(renderedDocumentToDelete); this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); } - - return Q(); } - public initDocumentEditorForNoOp(documentId: ConflictId): Q.Promise { + public async initDocumentEditorForNoOp(documentId: ConflictId): Promise { this.selectedConflictContent(null); this.selectedConflictCurrent(null); this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected); - return Q(); } protected getTabsButtons(): CommandButtonComponentProps[] { diff --git a/src/Explorer/Tabs/DatabaseSettingsTab.ts b/src/Explorer/Tabs/DatabaseSettingsTab.ts index ce6bf76d6..6aa98166e 100644 --- a/src/Explorer/Tabs/DatabaseSettingsTab.ts +++ b/src/Explorer/Tabs/DatabaseSettingsTab.ts @@ -8,7 +8,6 @@ import * as SharedConstants from "../../Shared/Constants"; import * as ViewModels from "../../Contracts/ViewModels"; import DiscardIcon from "../../../images/discard.svg"; import editable from "../../Common/EditableUtility"; -import Q from "q"; import SaveIcon from "../../../images/save-cosmos.svg"; import TabsBase from "./TabsBase"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; @@ -22,12 +21,12 @@ import { updateOfferThroughputBeyondLimit } from "../../Common/dataAccess/update import { configContext, Platform } from "../../ConfigContext"; const updateThroughputBeyondLimitWarningMessage: string = ` -You are about to request an increase in throughput beyond the pre-allocated capacity. -The service will scale out and increase throughput for the selected database. +You are about to request an increase in throughput beyond the pre-allocated capacity. +The service will scale out and increase throughput for the selected database. This operation will take 1-3 business days to complete. You can track the status of this request in Notifications.`; const updateThroughputDelayedApplyWarningMessage: string = ` -You are about to request an increase in throughput beyond the pre-allocated capacity. +You are about to request an increase in throughput beyond the pre-allocated capacity. This operation will take some time to complete.`; const currentThroughput: (isAutoscale: boolean, throughput: number) => string = (isAutoscale, throughput) => @@ -36,17 +35,17 @@ const currentThroughput: (isAutoscale: boolean, throughput: number) => string = : `Current manual throughput: ${throughput} RU/s`; const throughputApplyDelayedMessage = (isAutoscale: boolean, throughput: number, databaseName: string) => - `The request to increase the throughput has successfully been submitted. + `The request to increase the throughput has successfully been submitted. This operation will take 1-3 business days to complete. View the latest status in Notifications.
Database: ${databaseName}, ${currentThroughput(isAutoscale, throughput)}`; const throughputApplyShortDelayMessage = (isAutoscale: boolean, throughput: number, databaseName: string) => - `A request to increase the throughput is currently in progress. + `A request to increase the throughput is currently in progress. This operation will take some time to complete.
Database: ${databaseName}, ${currentThroughput(isAutoscale, throughput)}`; const throughputApplyLongDelayMessage = (isAutoscale: boolean, throughput: number, databaseName: string) => - `A request to increase the throughput is currently in progress. + `A request to increase the throughput is currently in progress. This operation will take 1-3 business days to complete. View the latest status in Notifications.
Database: ${databaseName}, ${currentThroughput(isAutoscale, throughput)}`; @@ -544,7 +543,7 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels. } }; - public onRevertClick = (): Q.Promise => { + public onRevertClick = async (): Promise => { this.throughput.setBaseline(this.throughput.getEditableOriginalValue()); this.isAutoPilotSelected.setBaseline(this.isAutoPilotSelected.getEditableOriginalValue()); if (!this.hasAutoPilotV2FeatureFlag()) { @@ -552,11 +551,9 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels. } else { this.selectedAutoPilotTier.setBaseline(this.selectedAutoPilotTier.getEditableOriginalValue()); } - - return Q(); }; - public onActivate(): Q.Promise { + public onActivate(): Promise { return super.onActivate().then(async () => { this.database.selectedSubnodeKind(ViewModels.CollectionTabKind.DatabaseSettings); await this.database.loadOffer(); diff --git a/src/Explorer/Tabs/DocumentsTab.ts b/src/Explorer/Tabs/DocumentsTab.ts index 1779e10a0..d9e8c882a 100644 --- a/src/Explorer/Tabs/DocumentsTab.ts +++ b/src/Explorer/Tabs/DocumentsTab.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import Q from "q"; import * as Constants from "../../Common/Constants"; import * as DataModels from "../../Contracts/DataModels"; import * as ViewModels from "../../Contracts/ViewModels"; @@ -340,24 +339,21 @@ export default class DocumentsTab extends TabsBase { return true; } - public onShowFilterClick(): Q.Promise { + public async onShowFilterClick(): Promise { this.isFilterCreated(true); this.isFilterExpanded(true); $(".filterDocExpanded").addClass("active"); $("#content").addClass("active"); $(".querydropdown").focus(); - - return Q(); } - public onHideFilterClick(): Q.Promise { + public async onHideFilterClick(): Promise { this.isFilterExpanded(false); $(".filterDocExpanded").removeClass("active"); $("#content").removeClass("active"); $(".queryButton").focus(); - return Q(); } public onCloseButtonKeyDown = (source: any, event: KeyboardEvent): boolean => { @@ -369,7 +365,7 @@ export default class DocumentsTab extends TabsBase { return true; }; - public onApplyFilterClick(): Q.Promise { + public onApplyFilterClick(): Promise { // clear documents grid this.documentIds([]); return this.createIterator() @@ -398,7 +394,7 @@ export default class DocumentsTab extends TabsBase { }); } - public refreshDocumentsGrid(): Q.Promise { + public refreshDocumentsGrid(): Promise { return this.onApplyFilterClick(); } @@ -411,19 +407,17 @@ export default class DocumentsTab extends TabsBase { return true; }; - public onDocumentIdClick(clickedDocumentId: DocumentId): Q.Promise { + public async onDocumentIdClick(clickedDocumentId: DocumentId): Promise { if (this.editorState() !== ViewModels.DocumentExplorerState.noDocumentSelected) { - return Q(); + return; } this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); - - return Q(); } - public onNewDocumentClick = (): Q.Promise => { + public onNewDocumentClick = async (): Promise => { if (this.isEditorDirty() && !this._isIgnoreDirtyEditor()) { - return Q(); + return; } this.selectedDocumentId(null); @@ -431,11 +425,9 @@ export default class DocumentsTab extends TabsBase { this.initialDocumentContent(defaultDocument); this.selectedDocumentContent.setBaseline(defaultDocument); this.editorState(ViewModels.DocumentExplorerState.newDocumentValid); - - return Q(); }; - public onSaveNewDocumentClick = (): Q.Promise => { + public onSaveNewDocumentClick = (): Promise => { this.isExecutionError(false); const startKey: number = TelemetryProcessor.traceStart(Action.CreateDocument, { databaseAccountName: this.collection && this.collection.container.databaseAccount().name, @@ -493,15 +485,13 @@ export default class DocumentsTab extends TabsBase { .finally(() => this.isExecuting(false)); }; - public onRevertNewDocumentClick = (): Q.Promise => { + public onRevertNewDocumentClick = async (): Promise => { this.initialDocumentContent(""); this.selectedDocumentContent(""); this.editorState(ViewModels.DocumentExplorerState.noDocumentSelected); - - return Q(); }; - public onSaveExisitingDocumentClick = (): Q.Promise => { + public onSaveExisitingDocumentClick = (): Promise => { const selectedDocumentId = this.selectedDocumentId(); const documentContent = JSON.parse(this.selectedDocumentContent()); @@ -560,15 +550,13 @@ export default class DocumentsTab extends TabsBase { .finally(() => this.isExecuting(false)); }; - public onRevertExisitingDocumentClick = (): Q.Promise => { + public onRevertExisitingDocumentClick = async (): Promise => { this.selectedDocumentContent.setBaseline(this.initialDocumentContent()); this.initialDocumentContent.valueHasMutated(); this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentNoEdits); - - return Q(); }; - public onDeleteExisitingDocumentClick = (): Q.Promise => { + public onDeleteExisitingDocumentClick = async (): Promise => { const selectedDocumentId = this.selectedDocumentId(); const msg = !this.isPreferredApiMongoDB ? "Are you sure you want to delete the selected item ?" @@ -577,30 +565,27 @@ export default class DocumentsTab extends TabsBase { if (window.confirm(msg)) { return this._deleteDocument(selectedDocumentId); } - - return Q(); }; - public onValidDocumentEdit(): Q.Promise { + public async onValidDocumentEdit(): Promise { if ( this.editorState() === ViewModels.DocumentExplorerState.newDocumentInvalid || this.editorState() === ViewModels.DocumentExplorerState.newDocumentValid ) { this.editorState(ViewModels.DocumentExplorerState.newDocumentValid); - return Q(); + return; } this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentDirtyValid); - return Q(); } - public onInvalidDocumentEdit(): Q.Promise { + public async onInvalidDocumentEdit(): Promise { if ( this.editorState() === ViewModels.DocumentExplorerState.newDocumentInvalid || this.editorState() === ViewModels.DocumentExplorerState.newDocumentValid ) { this.editorState(ViewModels.DocumentExplorerState.newDocumentInvalid); - return Q(); + return; } if ( @@ -608,22 +593,20 @@ export default class DocumentsTab extends TabsBase { this.editorState() === ViewModels.DocumentExplorerState.exisitingDocumentDirtyValid ) { this.editorState(ViewModels.DocumentExplorerState.exisitingDocumentDirtyInvalid); - return Q(); + return; } - - return Q(); } - public onTabClick(): Q.Promise { + public onTabClick(): Promise { return super.onTabClick().then(() => { this.collection && this.collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents); }); } - public onActivate(): Q.Promise { + public onActivate(): Promise { return super.onActivate().then(() => { if (this._documentsIterator) { - return Q.resolve(this._documentsIterator); + return this._documentsIterator; } return this.createIterator().then( @@ -653,7 +636,7 @@ export default class DocumentsTab extends TabsBase { }); } - public onRefreshClick(): Q.Promise { + public onRefreshClick(): Promise { return this.refreshDocumentsGrid().then(() => { this.selectedDocumentContent(""); this.selectedDocumentId(null); @@ -665,11 +648,11 @@ export default class DocumentsTab extends TabsBase { return window.confirm(msg); }; - protected __deleteDocument(documentId: DocumentId): Q.Promise { + protected __deleteDocument(documentId: DocumentId): Promise { return deleteDocument(this.collection, documentId); } - private _deleteDocument(selectedDocumentId: DocumentId): Q.Promise { + private _deleteDocument(selectedDocumentId: DocumentId): Promise { this.isExecutionError(false); const startKey: number = TelemetryProcessor.traceStart(Action.DeleteDocument, { databaseAccountName: this.collection && this.collection.container.databaseAccount().name, @@ -714,7 +697,7 @@ export default class DocumentsTab extends TabsBase { .finally(() => this.isExecuting(false)); } - public createIterator(): Q.Promise> { + public createIterator(): Promise> { let filters = this.lastFilterContents(); const filter: string = this.filterContent().trim(); const query: string = this.buildQuery(filter); @@ -728,14 +711,14 @@ export default class DocumentsTab extends TabsBase { return queryDocuments(this.collection.databaseId, this.collection.id(), query, options); } - public selectDocument(documentId: DocumentId): Q.Promise { + public selectDocument(documentId: DocumentId): Promise { this.selectedDocumentId(documentId); return readDocument(this.collection, documentId).then((content: any) => { this.initDocumentEditor(documentId, content); }); } - public loadNextPage(): Q.Promise { + public loadNextPage(): Promise { this.isExecuting(true); this.isExecutionError(false); return this._loadNextPageInternal() @@ -809,8 +792,8 @@ export default class DocumentsTab extends TabsBase { } }; - protected _loadNextPageInternal(): Q.Promise { - return Q(this._documentsIterator.fetchNext().then(response => response.resources)); + protected _loadNextPageInternal(): Promise { + return this._documentsIterator.fetchNext().then(response => response.resources); } protected _onEditorContentChange(newContent: string) { @@ -822,7 +805,7 @@ export default class DocumentsTab extends TabsBase { } } - public initDocumentEditor(documentId: DocumentId, documentContent: any): Q.Promise { + public async initDocumentEditor(documentId: DocumentId, documentContent: any): Promise { if (documentId) { const content: string = this.renderObjectForEditor(documentContent, null, 4); this.selectedDocumentContent.setBaseline(content); @@ -832,8 +815,6 @@ export default class DocumentsTab extends TabsBase { : ViewModels.DocumentExplorerState.newDocumentValid; this.editorState(newState); } - - return Q(); } public buildQuery(filter: string): string { diff --git a/src/Explorer/Tabs/GraphTab.ts b/src/Explorer/Tabs/GraphTab.ts index f17f7999f..e085334f0 100644 --- a/src/Explorer/Tabs/GraphTab.ts +++ b/src/Explorer/Tabs/GraphTab.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import * as Q from "q"; import * as ViewModels from "../../Contracts/ViewModels"; import TabsBase from "./TabsBase"; import { GraphExplorerAdapter } from "../Graph/GraphExplorerComponent/GraphExplorerAdapter"; @@ -114,7 +113,7 @@ export default class GraphTab extends TabsBase { : `${account.name}.graphs.azure.com:443/`; } - public onTabClick(): Q.Promise { + public onTabClick(): Promise { return super.onTabClick().then(() => { this.collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Graph); }); diff --git a/src/Explorer/Tabs/MongoQueryTab.ts b/src/Explorer/Tabs/MongoQueryTab.ts index 53ba3271e..11fd4d835 100644 --- a/src/Explorer/Tabs/MongoQueryTab.ts +++ b/src/Explorer/Tabs/MongoQueryTab.ts @@ -1,5 +1,4 @@ import * as ViewModels from "../../Contracts/ViewModels"; -import Q from "q"; import MongoUtility from "../../Common/MongoUtility"; import QueryTab from "./QueryTab"; import * as HeadersUtility from "../../Common/HeadersUtility"; @@ -20,10 +19,10 @@ export default class MongoQueryTab extends QueryTab { return MongoUtility.tojson(value, null, false); } - protected _initIterator(): Q.Promise { + protected async _initIterator(): Promise { let options: any = {}; options.enableCrossPartitionQuery = HeadersUtility.shouldEnableCrossPartitionKey(); this._iterator = queryIterator(this.collection.databaseId, this.collection, this.sqlStatementToExecute()); - return Q(this._iterator); + return this._iterator; } } diff --git a/src/Explorer/Tabs/MongoShellTab.ts b/src/Explorer/Tabs/MongoShellTab.ts index 04b9528b7..0b9143dd0 100644 --- a/src/Explorer/Tabs/MongoShellTab.ts +++ b/src/Explorer/Tabs/MongoShellTab.ts @@ -3,7 +3,6 @@ import * as ko from "knockout"; import * as ViewModels from "../../Contracts/ViewModels"; import AuthHeadersUtil from "../../Platform/Hosted/Authorization"; import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation"; -import Q from "q"; import TabsBase from "./TabsBase"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; @@ -53,7 +52,7 @@ export default class MongoShellTab extends TabsBase { // } } - public onTabClick(): Q.Promise { + public onTabClick(): Promise { return super.onTabClick().then(() => { this.collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents); }); diff --git a/src/Explorer/Tabs/NotebookV2Tab.ts b/src/Explorer/Tabs/NotebookV2Tab.ts index 88a692ec9..a00858d7b 100644 --- a/src/Explorer/Tabs/NotebookV2Tab.ts +++ b/src/Explorer/Tabs/NotebookV2Tab.ts @@ -1,5 +1,4 @@ import * as _ from "underscore"; -import * as Q from "q"; import * as ko from "knockout"; import * as ViewModels from "../../Contracts/ViewModels"; @@ -84,7 +83,7 @@ export default class NotebookTabV2 extends TabsBase { }); } - public onCloseTabButtonClick(): Q.Promise { + public async onCloseTabButtonClick(): Promise { const cleanup = () => { this.notebookComponentAdapter.notebookShutdown(); this.isActive(false); @@ -100,11 +99,11 @@ export default class NotebookTabV2 extends TabsBase { "Cancel", undefined ); - return Q.resolve(null); } else { cleanup(); - return Q.resolve(null); } + + return null; } public async reconfigureServiceEndpoints() { diff --git a/src/Explorer/Tabs/QueryTab.ts b/src/Explorer/Tabs/QueryTab.ts index c2cf92f91..45f48f10e 100644 --- a/src/Explorer/Tabs/QueryTab.ts +++ b/src/Explorer/Tabs/QueryTab.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import Q from "q"; import * as Constants from "../../Common/Constants"; import * as DataModels from "../../Contracts/DataModels"; import * as ViewModels from "../../Contracts/ViewModels"; @@ -163,13 +162,13 @@ export default class QueryTab extends TabsBase implements ViewModels.WaitsForTem this._buildCommandBarOptions(); } - public onTabClick(): Q.Promise { + public onTabClick(): Promise { return super.onTabClick().then(() => { this.collection && this.collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Query); }); } - public onExecuteQueryClick = (): Q.Promise => { + public onExecuteQueryClick = (): Promise => { const sqlStatement: string = this.selectedContent() || this.sqlQueryEditorContent(); this.sqlStatementToExecute(sqlStatement); this.allResultsMetadata([]); @@ -191,7 +190,7 @@ export default class QueryTab extends TabsBase implements ViewModels.WaitsForTem this.collection && this.collection.container && this.collection.container.browseQueriesPane.open(); }; - public onFetchNextPageClick(): Q.Promise { + public onFetchNextPageClick(): Promise { const allResultsMetadata = (this.allResultsMetadata && this.allResultsMetadata()) || []; const metadata: ViewModels.QueryResultsMetadata = allResultsMetadata[allResultsMetadata.length - 1]; const firstResultIndex: number = (metadata && Number(metadata.firstItemIndex)) || 1; @@ -265,7 +264,7 @@ export default class QueryTab extends TabsBase implements ViewModels.WaitsForTem return true; }; - private _executeQueryDocumentsPage(firstItemIndex: number): Q.Promise { + private _executeQueryDocumentsPage(firstItemIndex: number): Promise { this.errors([]); this.roundTrips(undefined); if (this._iterator == null) { @@ -277,7 +276,7 @@ export default class QueryTab extends TabsBase implements ViewModels.WaitsForTem } // TODO: Position and enable spinner when request is in progress - private _queryDocumentsPage(firstItemIndex: number): Q.Promise { + private _queryDocumentsPage(firstItemIndex: number): Promise { this.isExecutionError(false); this._resetAggregateQueryMetrics(); const startKey: number = TelemetryProcessor.traceStart(Action.ExecuteQuery, { @@ -485,16 +484,14 @@ export default class QueryTab extends TabsBase implements ViewModels.WaitsForTem } } - protected _initIterator(): Q.Promise { + protected _initIterator(): Promise { const options: any = QueryTab.getIteratorOptions(this.collection); if (this._resourceTokenPartitionKey) { options.partitionKey = this._resourceTokenPartitionKey; } - return Q( - queryDocuments(this.collection.databaseId, this.collection.id(), this.sqlStatementToExecute(), options).then( - iterator => (this._iterator = iterator) - ) + return queryDocuments(this.collection.databaseId, this.collection.id(), this.sqlStatementToExecute(), options).then( + iterator => (this._iterator = iterator) ); } diff --git a/src/Explorer/Tabs/QueryTablesTab.ts b/src/Explorer/Tabs/QueryTablesTab.ts index 6d4b50040..ef726763d 100644 --- a/src/Explorer/Tabs/QueryTablesTab.ts +++ b/src/Explorer/Tabs/QueryTablesTab.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import Q from "q"; import * as ViewModels from "../../Contracts/ViewModels"; import TabsBase from "./TabsBase"; import TableEntityListViewModel from "../Tables/DataTable/TableEntityListViewModel"; @@ -130,38 +129,38 @@ export default class QueryTablesTab extends TabsBase { this.buildCommandBarOptions(); } - public onExecuteQueryClick = (): Q.Promise => { + public onExecuteQueryClick = (): Promise => { this.queryViewModel().runQuery(); return null; }; - public onQueryBuilderClick = (): Q.Promise => { + public onQueryBuilderClick = (): Promise => { this.queryViewModel().selectHelper(); return null; }; - public onQueryTextClick = (): Q.Promise => { + public onQueryTextClick = (): Promise => { this.queryViewModel().selectEditor(); return null; }; - public onAddEntityClick = (): Q.Promise => { + public onAddEntityClick = (): Promise => { this.container.addTableEntityPane.tableViewModel = this.tableEntityListViewModel(); this.container.addTableEntityPane.open(); return null; }; - public onEditEntityClick = (): Q.Promise => { + public onEditEntityClick = (): Promise => { this.tableCommands.editEntityCommand(this.tableEntityListViewModel()); return null; }; - public onDeleteEntityClick = (): Q.Promise => { + public onDeleteEntityClick = (): Promise => { this.tableCommands.deleteEntitiesCommand(this.tableEntityListViewModel()); return null; }; - public onActivate(): Q.Promise { + public onActivate(): Promise { return super.onActivate().then(() => { const columns = !!this.tableEntityListViewModel() && diff --git a/src/Explorer/Tabs/ScriptTabBase.ts b/src/Explorer/Tabs/ScriptTabBase.ts index 2bcdab272..31f9234ee 100644 --- a/src/Explorer/Tabs/ScriptTabBase.ts +++ b/src/Explorer/Tabs/ScriptTabBase.ts @@ -1,6 +1,5 @@ import * as ko from "knockout"; import * as monaco from "monaco-editor"; -import Q from "q"; import DiscardIcon from "../../../images/discard.svg"; import SaveIcon from "../../../images/save-cosmos.svg"; import * as Constants from "../../Common/Constants"; @@ -186,7 +185,7 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode this._setBaselines(); } - public onTabClick(): Q.Promise { + public onTabClick(): Promise { return super.onTabClick().then(() => { if (this.isNew()) { this.collection.selectedSubnodeKind(this.tabKind); @@ -197,13 +196,11 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode public abstract onSaveClick: () => Promise; public abstract onUpdateClick: () => Promise; - public onDiscard = (): Q.Promise => { + public onDiscard = async (): Promise => { this.setBaselines(); const original = this.editorContent.getEditableOriginalValue(); const editorModel = this.editor() && this.editor().getModel(); editorModel && editorModel.setValue(original); - - return Q(); }; public onSaveOrUpdateClick(): Promise { diff --git a/src/Explorer/Tabs/SettingsTab.ts b/src/Explorer/Tabs/SettingsTab.ts index a3a3e68b8..84f0db13e 100644 --- a/src/Explorer/Tabs/SettingsTab.ts +++ b/src/Explorer/Tabs/SettingsTab.ts @@ -9,7 +9,6 @@ import * as SharedConstants from "../../Shared/Constants"; import * as ViewModels from "../../Contracts/ViewModels"; import DiscardIcon from "../../../images/discard.svg"; import editable from "../../Common/EditableUtility"; -import Q from "q"; import SaveIcon from "../../../images/save-cosmos.svg"; import TabsBase from "./TabsBase"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; @@ -24,21 +23,21 @@ import { updateOfferThroughputBeyondLimit } from "../../Common/dataAccess/update import { configContext, Platform } from "../../ConfigContext"; const ttlWarning: string = ` -The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application. +The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application. For more information see, Time to Live (TTL) in Azure Cosmos DB.`; const indexingPolicyTTLWarningMessage: string = ` -Changing the Indexing Policy impacts query results while the index transformation occurs. -When a change is made and the indexing mode is set to consistent or lazy, queries return eventual results until the operation completes. +Changing the Indexing Policy impacts query results while the index transformation occurs. +When a change is made and the indexing mode is set to consistent or lazy, queries return eventual results until the operation completes. For more information see, Modifying Indexing Policies.`; const updateThroughputBeyondLimitWarningMessage: string = ` -You are about to request an increase in throughput beyond the pre-allocated capacity. -The service will scale out and increase throughput for the selected container. +You are about to request an increase in throughput beyond the pre-allocated capacity. +The service will scale out and increase throughput for the selected container. This operation will take 1-3 business days to complete. You can track the status of this request in Notifications.`; const updateThroughputDelayedApplyWarningMessage: string = ` -You are about to request an increase in throughput beyond the pre-allocated capacity. +You are about to request an increase in throughput beyond the pre-allocated capacity. This operation will take some time to complete.`; // TODO: move to a utility classs and add unit tests @@ -82,7 +81,7 @@ const throughputApplyDelayedMessage = ( collectionName: string, requestedThroughput: number ): string => ` -The request to increase the throughput has successfully been submitted. +The request to increase the throughput has successfully been submitted. This operation will take 1-3 business days to complete. View the latest status in Notifications.
Database: ${databaseName}, Container: ${collectionName} ${currentThroughput( isAutoscale, @@ -115,7 +114,7 @@ const throughputApplyLongDelayMessage = ( collectionName: string, requestedThroughput: number ): string => ` -A request to increase the throughput is currently in progress. +A request to increase the throughput is currently in progress. This operation will take 1-3 business days to complete. View the latest status in Notifications.
Database: ${databaseName}, Container: ${collectionName} ${currentThroughput( isAutoscale, @@ -1231,7 +1230,7 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor this.isExecuting(false); }; - public onRevertClick = (): Q.Promise => { + public onRevertClick = async (): Promise => { TelemetryProcessor.trace(Action.DiscardSettings, ActionModifiers.Mark, { message: "Settings Discarded" }); @@ -1274,21 +1273,17 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor this.selectedAutoPilotTier(originalAutoPilotTier); } } - - return Q(); }; - public onValidIndexingPolicyEdit(): Q.Promise { + public async onValidIndexingPolicyEdit(): Promise { this.indexingPolicyContent.editableIsValid(true); - return Q(); } - public onInvalidIndexingPolicyEdit(): Q.Promise { + public async onInvalidIndexingPolicyEdit(): Promise { this.indexingPolicyContent.editableIsValid(false); - return Q(); } - public onActivate(): Q.Promise { + public onActivate(): Promise { return super.onActivate().then(async () => { this.collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Settings); const database: ViewModels.Database = this.collection.getDatabase(); diff --git a/src/Explorer/Tabs/SettingsTabV2.tsx b/src/Explorer/Tabs/SettingsTabV2.tsx index 149ccdd6d..70fb3c11d 100644 --- a/src/Explorer/Tabs/SettingsTabV2.tsx +++ b/src/Explorer/Tabs/SettingsTabV2.tsx @@ -41,7 +41,7 @@ export default class SettingsTabV2 extends TabsBase { }); } - public onActivate(): Q.Promise { + public onActivate(): Promise { this.isExecuting(true); this.currentCollection.loadOffer().then( () => { diff --git a/src/Explorer/Tabs/StoredProcedureTab.ts b/src/Explorer/Tabs/StoredProcedureTab.ts index 49065cb9e..74bfd28c8 100644 --- a/src/Explorer/Tabs/StoredProcedureTab.ts +++ b/src/Explorer/Tabs/StoredProcedureTab.ts @@ -1,6 +1,5 @@ import { Resource, StoredProcedureDefinition } from "@azure/cosmos"; import * as ko from "knockout"; -import Q from "q"; import * as _ from "underscore"; import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg"; import * as Constants from "../../Common/Constants"; @@ -61,13 +60,11 @@ export default class StoredProcedureTab extends ScriptTabBase { }); }; - public onDiscard = (): Q.Promise => { + public onDiscard = async (): Promise => { this.setBaselines(); const original = this.editorContent.getEditableOriginalValue(); this.originalSprocBody(original); this.originalSprocBody.valueHasMutated(); // trigger a re-render of the editor - - return Q(); }; public onUpdateClick = (): Promise => { @@ -284,8 +281,7 @@ export default class StoredProcedureTab extends ScriptTabBase { .finally(() => this.isExecuting(false)); } - public onDelete(): Q.Promise { + public async onDelete(): Promise { // TODO - return Q(); } } diff --git a/src/Explorer/Tabs/TabsBase.ts b/src/Explorer/Tabs/TabsBase.ts index b22b52339..ef8dc30af 100644 --- a/src/Explorer/Tabs/TabsBase.ts +++ b/src/Explorer/Tabs/TabsBase.ts @@ -1,5 +1,4 @@ import * as ko from "knockout"; -import Q from "q"; import * as Constants from "../../Common/Constants"; import * as ViewModels from "../../Contracts/ViewModels"; import * as DataModels from "../../Contracts/DataModels"; @@ -93,9 +92,8 @@ export default class TabsBase extends WaitsForTemplateViewModel { }); } - public onTabClick(): Q.Promise { + public async onTabClick(): Promise { this.getContainer().tabsManager.activateTab(this); - return Q(); } protected updateSelectedNode(): void { @@ -127,7 +125,7 @@ export default class TabsBase extends WaitsForTemplateViewModel { return this.onSpaceOrEnterKeyPress(event, () => this.onCloseTabButtonClick()); }; - public onActivate(): Q.Promise { + public async onActivate(): Promise { this.updateSelectedNode(); if (!!this.collection) { this.collection.selectedSubnodeKind(this.tabKind); @@ -149,7 +147,6 @@ export default class TabsBase extends WaitsForTemplateViewModel { tabTitle: this.tabTitle(), tabId: this.tabId }); - return Q(); } public onErrorDetailsClick = (src: any, event: MouseEvent): boolean => { @@ -172,9 +169,8 @@ export default class TabsBase extends WaitsForTemplateViewModel { return true; }; - public refresh(): Q.Promise { + public async refresh(): Promise { location.reload(); - return Q(); } protected getContainer(): Explorer { diff --git a/src/Explorer/Tree/ConflictId.ts b/src/Explorer/Tree/ConflictId.ts index 885f113fe..975cf632c 100644 --- a/src/Explorer/Tree/ConflictId.ts +++ b/src/Explorer/Tree/ConflictId.ts @@ -1,4 +1,3 @@ -import Q from "q"; import * as ko from "knockout"; import * as Constants from "../../Common/Constants"; import DocumentId from "./DocumentId"; @@ -59,13 +58,13 @@ export default class ConflictId { return; } - public loadConflict(): Q.Promise { + public async loadConflict(): Promise { const conflictsTab = this.container; this.container.selectedConflictId(this); if (this.operationType === Constants.ConflictOperationType.Create) { this.container.initDocumentEditorForCreate(this, this.content); - return Q(); + return; } this.container.loadingConflictData(true); @@ -88,10 +87,10 @@ export default class ConflictId { this.operationType === Constants.ConflictOperationType.Delete ) { this.container.initDocumentEditorForNoOp(this); - return Q(); + return; } - return Q.reject(reason); + throw reason; } ); } diff --git a/src/Explorer/Tree/DocumentId.ts b/src/Explorer/Tree/DocumentId.ts index 2e9a53bd3..03c3697c3 100644 --- a/src/Explorer/Tree/DocumentId.ts +++ b/src/Explorer/Tree/DocumentId.ts @@ -65,7 +65,7 @@ export default class DocumentId { return JSON.stringify(partitionKeyValue); } - public loadDocument(): Q.Promise { + public loadDocument(): Promise { return this.container.selectDocument(this); } } diff --git a/src/Explorer/Tree/ResourceTokenCollection.ts b/src/Explorer/Tree/ResourceTokenCollection.ts index 35361d23d..7c12ee87f 100644 --- a/src/Explorer/Tree/ResourceTokenCollection.ts +++ b/src/Explorer/Tree/ResourceTokenCollection.ts @@ -5,7 +5,6 @@ import * as ViewModels from "../../Contracts/ViewModels"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; import DocumentId from "./DocumentId"; import DocumentsTab from "../Tabs/DocumentsTab"; -import Q from "q"; import QueryTab from "../Tabs/QueryTab"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import Explorer from "../Explorer"; @@ -41,9 +40,9 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas this.isCollectionExpanded = ko.observable(true); } - public expandCollection(): Q.Promise { + public async expandCollection(): Promise { if (this.isCollectionExpanded()) { - return Q(); + return; } this.isCollectionExpanded(true); @@ -55,8 +54,6 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas defaultExperience: this.container.defaultExperience(), dataExplorerArea: Constants.Areas.ResourceTree }); - - return Q.resolve(); } public collapseCollection() { diff --git a/src/Utils/QueryUtils.ts b/src/Utils/QueryUtils.ts index 1f33b7094..dd211e5a2 100644 --- a/src/Utils/QueryUtils.ts +++ b/src/Utils/QueryUtils.ts @@ -1,4 +1,3 @@ -import Q from "q"; import * as DataModels from "../Contracts/DataModels"; import * as ViewModels from "../Contracts/ViewModels"; @@ -60,39 +59,34 @@ export class QueryUtils { public static queryPagesUntilContentPresent( firstItemIndex: number, - queryItems: (itemIndex: number) => Q.Promise - ): Q.Promise { + queryItems: (itemIndex: number) => Promise + ): Promise { let roundTrips: number = 0; let netRequestCharge: number = 0; - const doRequest = (itemIndex: number): Q.Promise => - queryItems(itemIndex).then( - (results: ViewModels.QueryResults) => { - roundTrips = roundTrips + 1; - results.roundTrips = roundTrips; - results.requestCharge = Number(results.requestCharge) + netRequestCharge; - netRequestCharge = Number(results.requestCharge); - const resultsMetadata: ViewModels.QueryResultsMetadata = { - hasMoreResults: results.hasMoreResults, - itemCount: results.itemCount, - firstItemIndex: results.firstItemIndex, - lastItemIndex: results.lastItemIndex - }; - if (resultsMetadata.itemCount === 0 && resultsMetadata.hasMoreResults) { - return doRequest(resultsMetadata.lastItemIndex); - } - return Q.resolve(results); - }, - (error: any) => { - return Q.reject(error); + const doRequest = async (itemIndex: number): Promise => + queryItems(itemIndex).then((results: ViewModels.QueryResults) => { + roundTrips = roundTrips + 1; + results.roundTrips = roundTrips; + results.requestCharge = Number(results.requestCharge) + netRequestCharge; + netRequestCharge = Number(results.requestCharge); + const resultsMetadata: ViewModels.QueryResultsMetadata = { + hasMoreResults: results.hasMoreResults, + itemCount: results.itemCount, + firstItemIndex: results.firstItemIndex, + lastItemIndex: results.lastItemIndex + }; + if (resultsMetadata.itemCount === 0 && resultsMetadata.hasMoreResults) { + return doRequest(resultsMetadata.lastItemIndex); } - ); + return results; + }); return doRequest(firstItemIndex); } public static queryAllPages( - queryItems: (itemIndex: number) => Q.Promise - ): Q.Promise { + queryItems: (itemIndex: number) => Promise + ): Promise { const queryResults: ViewModels.QueryResults = { documents: [], activityId: undefined, @@ -103,25 +97,20 @@ export class QueryUtils { requestCharge: 0, roundTrips: 0 }; - const doRequest = (itemIndex: number): Q.Promise => - queryItems(itemIndex).then( - (results: ViewModels.QueryResults) => { - const { requestCharge, hasMoreResults, itemCount, lastItemIndex, documents } = results; - queryResults.roundTrips = queryResults.roundTrips + 1; - queryResults.requestCharge = Number(queryResults.requestCharge) + Number(requestCharge); - queryResults.hasMoreResults = hasMoreResults; - queryResults.itemCount = queryResults.itemCount + itemCount; - queryResults.lastItemIndex = lastItemIndex; - queryResults.documents = queryResults.documents.concat(documents); - if (queryResults.hasMoreResults) { - return doRequest(queryResults.lastItemIndex + 1); - } - return Q.resolve(queryResults); - }, - (error: any) => { - return Q.reject(error); + const doRequest = async (itemIndex: number): Promise => + queryItems(itemIndex).then((results: ViewModels.QueryResults) => { + const { requestCharge, hasMoreResults, itemCount, lastItemIndex, documents } = results; + queryResults.roundTrips = queryResults.roundTrips + 1; + queryResults.requestCharge = Number(queryResults.requestCharge) + Number(requestCharge); + queryResults.hasMoreResults = hasMoreResults; + queryResults.itemCount = queryResults.itemCount + itemCount; + queryResults.lastItemIndex = lastItemIndex; + queryResults.documents = queryResults.documents.concat(documents); + if (queryResults.hasMoreResults) { + return doRequest(queryResults.lastItemIndex + 1); } - ); + return queryResults; + }); return doRequest(0); }