mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-25 15:06:55 +00:00
Remove Q from ViewModels (#390)
I got cold feet at the thought of merging #324 in one go, so I'm going to split it into smaller chunks and keep rebasing the large one until there's no more Q.
This commit is contained in:
parent
bddb288a89
commit
f8ede0cc1e
@ -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";
|
||||
@ -109,7 +108,7 @@ export interface CollectionBase extends TreeNode {
|
||||
|
||||
onDocumentDBDocumentsClick(): void;
|
||||
onNewQueryClick(source: any, event: MouseEvent, queryText?: string): void;
|
||||
expandCollection(): Q.Promise<any>;
|
||||
expandCollection(): void;
|
||||
collapseCollection(): void;
|
||||
getDatabase(): Database;
|
||||
}
|
||||
@ -176,7 +175,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<UploadDetails>;
|
||||
uploadFiles(fileList: FileList): Promise<UploadDetails>;
|
||||
|
||||
getLabel(): string;
|
||||
}
|
||||
@ -294,7 +293,7 @@ export interface DocumentsTabOptions extends TabOptions {
|
||||
}
|
||||
|
||||
export interface SettingsTabV2Options extends TabOptions {
|
||||
getPendingNotification: Q.Promise<DataModels.Notification>;
|
||||
getPendingNotification: Promise<DataModels.Notification>;
|
||||
}
|
||||
|
||||
export interface ConflictsTabOptions extends TabOptions {
|
||||
|
@ -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<DataModels.Notification>(() => {
|
||||
return;
|
||||
}),
|
||||
getPendingNotification: Promise.resolve(undefined),
|
||||
}),
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Resource, StoredProcedureDefinition, TriggerDefinition, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||
import * as ko from "knockout";
|
||||
import Q from "q";
|
||||
import * as _ from "underscore";
|
||||
import UploadWorker from "worker-loader!../../workers/upload";
|
||||
import { AuthType } from "../../AuthType";
|
||||
@ -254,9 +253,9 @@ export default class Collection implements ViewModels.Collection {
|
||||
});
|
||||
}
|
||||
|
||||
public expandCollection(): Q.Promise<any> {
|
||||
public expandCollection(): void {
|
||||
if (this.isCollectionExpanded()) {
|
||||
return Q();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isCollectionExpanded(true);
|
||||
@ -268,8 +267,6 @@ export default class Collection implements ViewModels.Collection {
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||
});
|
||||
|
||||
return Q.resolve();
|
||||
}
|
||||
|
||||
public onDocumentDBDocumentsClick() {
|
||||
@ -547,7 +544,7 @@ export default class Collection implements ViewModels.Collection {
|
||||
});
|
||||
|
||||
const tabTitle = !this.offer() ? "Settings" : "Scale & Settings";
|
||||
const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification();
|
||||
const pendingNotificationsPromise: Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification();
|
||||
const matchingTabs = this.container.tabsManager.getTabs(ViewModels.CollectionTabKind.SettingsV2, (tab) => {
|
||||
return tab.collection && tab.collection.databaseId === this.databaseId && tab.collection.id() === this.id();
|
||||
});
|
||||
@ -580,7 +577,7 @@ export default class Collection implements ViewModels.Collection {
|
||||
settingsTabV2: SettingsTabV2,
|
||||
traceStartData: any,
|
||||
settingsTabOptions: ViewModels.TabOptions,
|
||||
getPendingNotification: Q.Promise<DataModels.Notification>
|
||||
getPendingNotification: Promise<DataModels.Notification>
|
||||
): void => {
|
||||
const settingsTabV2Options: ViewModels.SettingsTabV2Options = {
|
||||
...settingsTabOptions,
|
||||
@ -980,19 +977,19 @@ export default class Collection implements ViewModels.Collection {
|
||||
this.container.deleteCollectionConfirmationPane.open();
|
||||
}
|
||||
|
||||
public uploadFiles = (fileList: FileList): Q.Promise<UploadDetails> => {
|
||||
public uploadFiles = (fileList: FileList): Promise<UploadDetails> => {
|
||||
// TODO: right now web worker is not working with AAD flow. Use main thread for upload for now until we have backend upload capability
|
||||
if (configContext.platform === Platform.Hosted && window.authType === AuthType.AAD) {
|
||||
return this._uploadFilesCors(fileList);
|
||||
}
|
||||
const documentUploader: Worker = new UploadWorker();
|
||||
const deferred: Q.Deferred<UploadDetails> = Q.defer<UploadDetails>();
|
||||
let inProgressNotificationId: string = "";
|
||||
|
||||
if (!fileList || fileList.length === 0) {
|
||||
return Q.reject("No files specified");
|
||||
return Promise.reject("No files specified");
|
||||
}
|
||||
documentUploader.onmessage = (event: MessageEvent) => {
|
||||
|
||||
const onmessage = (resolve: (value: UploadDetails) => void, reject: (reason: any) => void, event: MessageEvent) => {
|
||||
const numSuccessful: number = event.data.numUploadsSuccessful;
|
||||
const numFailed: number = event.data.numUploadsFailed;
|
||||
const runtimeError: string = event.data.runtimeError;
|
||||
@ -1001,31 +998,26 @@ export default class Collection implements ViewModels.Collection {
|
||||
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressNotificationId);
|
||||
documentUploader.terminate();
|
||||
if (!!runtimeError) {
|
||||
deferred.reject(runtimeError);
|
||||
reject(runtimeError);
|
||||
} else if (numSuccessful === 0) {
|
||||
// all uploads failed
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to upload all documents to container ${this.id()}`
|
||||
);
|
||||
NotificationConsoleUtils.logConsoleError(`Failed to upload all documents to container ${this.id()}`);
|
||||
} else if (numFailed > 0) {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Error,
|
||||
NotificationConsoleUtils.logConsoleError(
|
||||
`Failed to upload ${numFailed} of ${numSuccessful + numFailed} documents to container ${this.id()}`
|
||||
);
|
||||
} else {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.Info,
|
||||
NotificationConsoleUtils.logConsoleInfo(
|
||||
`Successfully uploaded all ${numSuccessful} documents to container ${this.id()}`
|
||||
);
|
||||
}
|
||||
this._logUploadDetailsInConsole(uploadDetails);
|
||||
deferred.resolve(uploadDetails);
|
||||
resolve(uploadDetails);
|
||||
};
|
||||
documentUploader.onerror = (event: ErrorEvent): void => {
|
||||
function onerror(reject: (reason: any) => void, event: ErrorEvent) {
|
||||
documentUploader.terminate();
|
||||
deferred.reject(event.error);
|
||||
};
|
||||
reject(event.error);
|
||||
}
|
||||
|
||||
const uploaderMessage: StartUploadMessageParams = {
|
||||
files: fileList,
|
||||
@ -1040,42 +1032,33 @@ export default class Collection implements ViewModels.Collection {
|
||||
},
|
||||
};
|
||||
|
||||
return new Promise<UploadDetails>((resolve, reject) => {
|
||||
documentUploader.onmessage = onmessage.bind(null, resolve, reject);
|
||||
documentUploader.onerror = onerror.bind(null, reject);
|
||||
|
||||
documentUploader.postMessage(uploaderMessage);
|
||||
inProgressNotificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||
ConsoleDataType.InProgress,
|
||||
`Uploading and creating documents in container ${this.id()}`
|
||||
);
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
};
|
||||
|
||||
private _uploadFilesCors(files: FileList): Q.Promise<UploadDetails> {
|
||||
const deferred: Q.Deferred<UploadDetails> = Q.defer<UploadDetails>();
|
||||
const promises: Array<Q.Promise<UploadDetailsRecord>> = [];
|
||||
private async _uploadFilesCors(files: FileList): Promise<UploadDetails> {
|
||||
const data = await Promise.all(Array.from(files).map((file) => this._uploadFile(file)));
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
promises.push(this._uploadFile(files[i]));
|
||||
}
|
||||
Q.all(promises).then((uploadDetails: Array<UploadDetailsRecord>) => {
|
||||
deferred.resolve({ data: uploadDetails });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
return { data };
|
||||
}
|
||||
|
||||
private _uploadFile(file: File): Q.Promise<UploadDetailsRecord> {
|
||||
const deferred: Q.Deferred<UploadDetailsRecord> = Q.defer();
|
||||
|
||||
private _uploadFile(file: File): Promise<UploadDetailsRecord> {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (evt: any): void => {
|
||||
const onload = (resolve: (value: UploadDetailsRecord) => void, evt: any): void => {
|
||||
const fileData: string = evt.target.result;
|
||||
this._createDocumentsFromFile(file.name, fileData).then((record) => {
|
||||
deferred.resolve(record);
|
||||
});
|
||||
this._createDocumentsFromFile(file.name, fileData).then((record) => resolve(record));
|
||||
};
|
||||
|
||||
reader.onerror = (evt: ProgressEvent): void => {
|
||||
deferred.resolve({
|
||||
const onerror = (resolve: (value: UploadDetailsRecord) => void, evt: ProgressEvent): void => {
|
||||
resolve({
|
||||
fileName: file.name,
|
||||
numSucceeded: 0,
|
||||
numFailed: 1,
|
||||
@ -1083,9 +1066,11 @@ export default class Collection implements ViewModels.Collection {
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise<UploadDetailsRecord>((resolve) => {
|
||||
reader.onload = onload.bind(this, resolve);
|
||||
reader.onerror = onerror.bind(this, resolve);
|
||||
reader.readAsText(file);
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
}
|
||||
|
||||
private async _createDocumentsFromFile(fileName: string, documentContent: string): Promise<UploadDetailsRecord> {
|
||||
@ -1119,32 +1104,23 @@ export default class Collection implements ViewModels.Collection {
|
||||
}
|
||||
}
|
||||
|
||||
private _getPendingThroughputSplitNotification(): Q.Promise<DataModels.Notification> {
|
||||
private async _getPendingThroughputSplitNotification(): Promise<DataModels.Notification> {
|
||||
if (!this.container) {
|
||||
return Q.resolve(undefined);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const deferred: Q.Deferred<DataModels.Notification> = Q.defer<DataModels.Notification>();
|
||||
fetchPortalNotifications().then(
|
||||
(notifications: DataModels.Notification[]) => {
|
||||
if (!notifications || notifications.length === 0) {
|
||||
deferred.resolve(undefined);
|
||||
return;
|
||||
const throughputUpdateRegExp = new RegExp("Throughput update (.*) in progress");
|
||||
try {
|
||||
const notifications = await fetchPortalNotifications();
|
||||
if (!notifications) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const pendingNotification = _.find(notifications, (notification: DataModels.Notification) => {
|
||||
const throughputUpdateRegExp: RegExp = new RegExp("Throughput update (.*) in progress");
|
||||
return (
|
||||
notification.kind === "message" &&
|
||||
notification.collectionName === this.id() &&
|
||||
notification.description &&
|
||||
throughputUpdateRegExp.test(notification.description)
|
||||
return notifications.find(
|
||||
({ kind, collectionName, description = "" }) =>
|
||||
kind === "message" && collectionName === this.id() && throughputUpdateRegExp.test(description)
|
||||
);
|
||||
});
|
||||
|
||||
deferred.resolve(pendingNotification);
|
||||
},
|
||||
(error: any) => {
|
||||
} catch (error) {
|
||||
Logger.logError(
|
||||
JSON.stringify({
|
||||
error: getErrorMessage(error),
|
||||
@ -1154,11 +1130,9 @@ export default class Collection implements ViewModels.Collection {
|
||||
}),
|
||||
"Settings tree node"
|
||||
);
|
||||
deferred.resolve(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
return deferred.promise;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _logUploadDetailsInConsole(uploadDetails: UploadDetails): void {
|
||||
|
@ -41,9 +41,9 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
|
||||
this.isCollectionExpanded = ko.observable<boolean>(true);
|
||||
}
|
||||
|
||||
public expandCollection(): Q.Promise<void> {
|
||||
public expandCollection(): void {
|
||||
if (this.isCollectionExpanded()) {
|
||||
return Q();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isCollectionExpanded(true);
|
||||
@ -55,8 +55,6 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||
});
|
||||
|
||||
return Q.resolve();
|
||||
}
|
||||
|
||||
public collapseCollection() {
|
||||
|
@ -288,12 +288,10 @@ export class TabRouteHandler {
|
||||
private _openSprocTabForResource(databaseId: string, collectionId: string, sprocId: string): void {
|
||||
this._executeActionHelper(() => {
|
||||
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
||||
collection &&
|
||||
collection.expandCollection().then(() => {
|
||||
collection && collection.expandCollection();
|
||||
const storedProcedure = collection && collection.findStoredProcedureWithId(sprocId);
|
||||
storedProcedure && storedProcedure.open();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _openNewTriggerTabForResource(databaseId: string, collectionId: string): void {
|
||||
@ -319,12 +317,10 @@ export class TabRouteHandler {
|
||||
private _openTriggerTabForResource(databaseId: string, collectionId: string, triggerId: string): void {
|
||||
this._executeActionHelper(() => {
|
||||
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
||||
collection &&
|
||||
collection.expandCollection().then(() => {
|
||||
collection && collection.expandCollection();
|
||||
const trigger = collection && collection.findTriggerWithId(triggerId);
|
||||
trigger && trigger.open();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _openNewUserDefinedFunctionTabForResource(databaseId: string, collectionId: string): void {
|
||||
@ -350,12 +346,10 @@ export class TabRouteHandler {
|
||||
private _openUserDefinedFunctionTabForResource(databaseId: string, collectionId: string, udfId: string): void {
|
||||
this._executeActionHelper(() => {
|
||||
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
||||
collection &&
|
||||
collection.expandCollection().then(() => {
|
||||
collection && collection.expandCollection();
|
||||
const userDefinedFunction = collection && collection.findUserDefinedFunctionWithId(udfId);
|
||||
userDefinedFunction && userDefinedFunction.open();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _openConflictsTabForResource(databaseId: string, collectionId: string): void {
|
||||
|
Loading…
Reference in New Issue
Block a user