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,
|
TriggerDefinition,
|
||||||
UserDefinedFunctionDefinition,
|
UserDefinedFunctionDefinition,
|
||||||
} from "@azure/cosmos";
|
} from "@azure/cosmos";
|
||||||
import Q from "q";
|
|
||||||
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../Explorer/Controls/CommandButton/CommandButtonComponent";
|
||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
@ -109,7 +108,7 @@ export interface CollectionBase extends TreeNode {
|
|||||||
|
|
||||||
onDocumentDBDocumentsClick(): void;
|
onDocumentDBDocumentsClick(): void;
|
||||||
onNewQueryClick(source: any, event: MouseEvent, queryText?: string): void;
|
onNewQueryClick(source: any, event: MouseEvent, queryText?: string): void;
|
||||||
expandCollection(): Q.Promise<any>;
|
expandCollection(): void;
|
||||||
collapseCollection(): void;
|
collapseCollection(): void;
|
||||||
getDatabase(): Database;
|
getDatabase(): Database;
|
||||||
}
|
}
|
||||||
@ -176,7 +175,7 @@ export interface Collection extends CollectionBase {
|
|||||||
|
|
||||||
onDragOver(source: Collection, event: { originalEvent: DragEvent }): void;
|
onDragOver(source: Collection, event: { originalEvent: DragEvent }): void;
|
||||||
onDrop(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;
|
getLabel(): string;
|
||||||
}
|
}
|
||||||
@ -294,7 +293,7 @@ export interface DocumentsTabOptions extends TabOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SettingsTabV2Options extends TabOptions {
|
export interface SettingsTabV2Options extends TabOptions {
|
||||||
getPendingNotification: Q.Promise<DataModels.Notification>;
|
getPendingNotification: Promise<DataModels.Notification>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConflictsTabOptions extends TabOptions {
|
export interface ConflictsTabOptions extends TabOptions {
|
||||||
|
@ -31,7 +31,6 @@ jest.mock("../../../Common/dataAccess/updateCollection", () => ({
|
|||||||
}));
|
}));
|
||||||
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
||||||
import { MongoDBCollectionResource } from "../../../Utils/arm/generatedClients/2020-04-01/types";
|
import { MongoDBCollectionResource } from "../../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import Q from "q";
|
|
||||||
jest.mock("../../../Common/dataAccess/updateOffer", () => ({
|
jest.mock("../../../Common/dataAccess/updateOffer", () => ({
|
||||||
updateOffer: jest.fn().mockReturnValue({} as DataModels.Offer),
|
updateOffer: jest.fn().mockReturnValue({} as DataModels.Offer),
|
||||||
}));
|
}));
|
||||||
@ -47,9 +46,7 @@ describe("SettingsComponent", () => {
|
|||||||
hashLocation: "settings",
|
hashLocation: "settings",
|
||||||
isActive: ko.observable(false),
|
isActive: ko.observable(false),
|
||||||
onUpdateTabsButtons: undefined,
|
onUpdateTabsButtons: undefined,
|
||||||
getPendingNotification: Q.Promise<DataModels.Notification>(() => {
|
getPendingNotification: Promise.resolve(undefined),
|
||||||
return;
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Resource, StoredProcedureDefinition, TriggerDefinition, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
import { Resource, StoredProcedureDefinition, TriggerDefinition, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import Q from "q";
|
|
||||||
import * as _ from "underscore";
|
import * as _ from "underscore";
|
||||||
import UploadWorker from "worker-loader!../../workers/upload";
|
import UploadWorker from "worker-loader!../../workers/upload";
|
||||||
import { AuthType } from "../../AuthType";
|
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()) {
|
if (this.isCollectionExpanded()) {
|
||||||
return Q();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isCollectionExpanded(true);
|
this.isCollectionExpanded(true);
|
||||||
@ -268,8 +267,6 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
defaultExperience: this.container.defaultExperience(),
|
defaultExperience: this.container.defaultExperience(),
|
||||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||||
});
|
});
|
||||||
|
|
||||||
return Q.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onDocumentDBDocumentsClick() {
|
public onDocumentDBDocumentsClick() {
|
||||||
@ -547,7 +544,7 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const tabTitle = !this.offer() ? "Settings" : "Scale & Settings";
|
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) => {
|
const matchingTabs = this.container.tabsManager.getTabs(ViewModels.CollectionTabKind.SettingsV2, (tab) => {
|
||||||
return tab.collection && tab.collection.databaseId === this.databaseId && tab.collection.id() === this.id();
|
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,
|
settingsTabV2: SettingsTabV2,
|
||||||
traceStartData: any,
|
traceStartData: any,
|
||||||
settingsTabOptions: ViewModels.TabOptions,
|
settingsTabOptions: ViewModels.TabOptions,
|
||||||
getPendingNotification: Q.Promise<DataModels.Notification>
|
getPendingNotification: Promise<DataModels.Notification>
|
||||||
): void => {
|
): void => {
|
||||||
const settingsTabV2Options: ViewModels.SettingsTabV2Options = {
|
const settingsTabV2Options: ViewModels.SettingsTabV2Options = {
|
||||||
...settingsTabOptions,
|
...settingsTabOptions,
|
||||||
@ -980,19 +977,19 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
this.container.deleteCollectionConfirmationPane.open();
|
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
|
// 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) {
|
if (configContext.platform === Platform.Hosted && window.authType === AuthType.AAD) {
|
||||||
return this._uploadFilesCors(fileList);
|
return this._uploadFilesCors(fileList);
|
||||||
}
|
}
|
||||||
const documentUploader: Worker = new UploadWorker();
|
const documentUploader: Worker = new UploadWorker();
|
||||||
const deferred: Q.Deferred<UploadDetails> = Q.defer<UploadDetails>();
|
|
||||||
let inProgressNotificationId: string = "";
|
let inProgressNotificationId: string = "";
|
||||||
|
|
||||||
if (!fileList || fileList.length === 0) {
|
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 numSuccessful: number = event.data.numUploadsSuccessful;
|
||||||
const numFailed: number = event.data.numUploadsFailed;
|
const numFailed: number = event.data.numUploadsFailed;
|
||||||
const runtimeError: string = event.data.runtimeError;
|
const runtimeError: string = event.data.runtimeError;
|
||||||
@ -1001,31 +998,26 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressNotificationId);
|
NotificationConsoleUtils.clearInProgressMessageWithId(inProgressNotificationId);
|
||||||
documentUploader.terminate();
|
documentUploader.terminate();
|
||||||
if (!!runtimeError) {
|
if (!!runtimeError) {
|
||||||
deferred.reject(runtimeError);
|
reject(runtimeError);
|
||||||
} else if (numSuccessful === 0) {
|
} else if (numSuccessful === 0) {
|
||||||
// all uploads failed
|
// all uploads failed
|
||||||
NotificationConsoleUtils.logConsoleMessage(
|
NotificationConsoleUtils.logConsoleError(`Failed to upload all documents to container ${this.id()}`);
|
||||||
ConsoleDataType.Error,
|
|
||||||
`Failed to upload all documents to container ${this.id()}`
|
|
||||||
);
|
|
||||||
} else if (numFailed > 0) {
|
} else if (numFailed > 0) {
|
||||||
NotificationConsoleUtils.logConsoleMessage(
|
NotificationConsoleUtils.logConsoleError(
|
||||||
ConsoleDataType.Error,
|
|
||||||
`Failed to upload ${numFailed} of ${numSuccessful + numFailed} documents to container ${this.id()}`
|
`Failed to upload ${numFailed} of ${numSuccessful + numFailed} documents to container ${this.id()}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
NotificationConsoleUtils.logConsoleMessage(
|
NotificationConsoleUtils.logConsoleInfo(
|
||||||
ConsoleDataType.Info,
|
|
||||||
`Successfully uploaded all ${numSuccessful} documents to container ${this.id()}`
|
`Successfully uploaded all ${numSuccessful} documents to container ${this.id()}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this._logUploadDetailsInConsole(uploadDetails);
|
this._logUploadDetailsInConsole(uploadDetails);
|
||||||
deferred.resolve(uploadDetails);
|
resolve(uploadDetails);
|
||||||
};
|
};
|
||||||
documentUploader.onerror = (event: ErrorEvent): void => {
|
function onerror(reject: (reason: any) => void, event: ErrorEvent) {
|
||||||
documentUploader.terminate();
|
documentUploader.terminate();
|
||||||
deferred.reject(event.error);
|
reject(event.error);
|
||||||
};
|
}
|
||||||
|
|
||||||
const uploaderMessage: StartUploadMessageParams = {
|
const uploaderMessage: StartUploadMessageParams = {
|
||||||
files: fileList,
|
files: fileList,
|
||||||
@ -1040,42 +1032,33 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
documentUploader.postMessage(uploaderMessage);
|
return new Promise<UploadDetails>((resolve, reject) => {
|
||||||
inProgressNotificationId = NotificationConsoleUtils.logConsoleMessage(
|
documentUploader.onmessage = onmessage.bind(null, resolve, reject);
|
||||||
ConsoleDataType.InProgress,
|
documentUploader.onerror = onerror.bind(null, reject);
|
||||||
`Uploading and creating documents in container ${this.id()}`
|
|
||||||
);
|
|
||||||
|
|
||||||
return deferred.promise;
|
documentUploader.postMessage(uploaderMessage);
|
||||||
|
inProgressNotificationId = NotificationConsoleUtils.logConsoleMessage(
|
||||||
|
ConsoleDataType.InProgress,
|
||||||
|
`Uploading and creating documents in container ${this.id()}`
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private _uploadFilesCors(files: FileList): Q.Promise<UploadDetails> {
|
private async _uploadFilesCors(files: FileList): Promise<UploadDetails> {
|
||||||
const deferred: Q.Deferred<UploadDetails> = Q.defer<UploadDetails>();
|
const data = await Promise.all(Array.from(files).map((file) => this._uploadFile(file)));
|
||||||
const promises: Array<Q.Promise<UploadDetailsRecord>> = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
return { data };
|
||||||
promises.push(this._uploadFile(files[i]));
|
|
||||||
}
|
|
||||||
Q.all(promises).then((uploadDetails: Array<UploadDetailsRecord>) => {
|
|
||||||
deferred.resolve({ data: uploadDetails });
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _uploadFile(file: File): Q.Promise<UploadDetailsRecord> {
|
private _uploadFile(file: File): Promise<UploadDetailsRecord> {
|
||||||
const deferred: Q.Deferred<UploadDetailsRecord> = Q.defer();
|
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (evt: any): void => {
|
const onload = (resolve: (value: UploadDetailsRecord) => void, evt: any): void => {
|
||||||
const fileData: string = evt.target.result;
|
const fileData: string = evt.target.result;
|
||||||
this._createDocumentsFromFile(file.name, fileData).then((record) => {
|
this._createDocumentsFromFile(file.name, fileData).then((record) => resolve(record));
|
||||||
deferred.resolve(record);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
reader.onerror = (evt: ProgressEvent): void => {
|
const onerror = (resolve: (value: UploadDetailsRecord) => void, evt: ProgressEvent): void => {
|
||||||
deferred.resolve({
|
resolve({
|
||||||
fileName: file.name,
|
fileName: file.name,
|
||||||
numSucceeded: 0,
|
numSucceeded: 0,
|
||||||
numFailed: 1,
|
numFailed: 1,
|
||||||
@ -1083,9 +1066,11 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
reader.readAsText(file);
|
return new Promise<UploadDetailsRecord>((resolve) => {
|
||||||
|
reader.onload = onload.bind(this, resolve);
|
||||||
return deferred.promise;
|
reader.onerror = onerror.bind(this, resolve);
|
||||||
|
reader.readAsText(file);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _createDocumentsFromFile(fileName: string, documentContent: string): Promise<UploadDetailsRecord> {
|
private async _createDocumentsFromFile(fileName: string, documentContent: string): Promise<UploadDetailsRecord> {
|
||||||
@ -1119,46 +1104,35 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getPendingThroughputSplitNotification(): Q.Promise<DataModels.Notification> {
|
private async _getPendingThroughputSplitNotification(): Promise<DataModels.Notification> {
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
return Q.resolve(undefined);
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deferred: Q.Deferred<DataModels.Notification> = Q.defer<DataModels.Notification>();
|
const throughputUpdateRegExp = new RegExp("Throughput update (.*) in progress");
|
||||||
fetchPortalNotifications().then(
|
try {
|
||||||
(notifications: DataModels.Notification[]) => {
|
const notifications = await fetchPortalNotifications();
|
||||||
if (!notifications || notifications.length === 0) {
|
if (!notifications) {
|
||||||
deferred.resolve(undefined);
|
return undefined;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
deferred.resolve(pendingNotification);
|
|
||||||
},
|
|
||||||
(error: any) => {
|
|
||||||
Logger.logError(
|
|
||||||
JSON.stringify({
|
|
||||||
error: getErrorMessage(error),
|
|
||||||
accountName: this.container && this.container.databaseAccount(),
|
|
||||||
databaseName: this.databaseId,
|
|
||||||
collectionName: this.id(),
|
|
||||||
}),
|
|
||||||
"Settings tree node"
|
|
||||||
);
|
|
||||||
deferred.resolve(undefined);
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
return deferred.promise;
|
return notifications.find(
|
||||||
|
({ kind, collectionName, description = "" }) =>
|
||||||
|
kind === "message" && collectionName === this.id() && throughputUpdateRegExp.test(description)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
Logger.logError(
|
||||||
|
JSON.stringify({
|
||||||
|
error: getErrorMessage(error),
|
||||||
|
accountName: this.container && this.container.databaseAccount(),
|
||||||
|
databaseName: this.databaseId,
|
||||||
|
collectionName: this.id(),
|
||||||
|
}),
|
||||||
|
"Settings tree node"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _logUploadDetailsInConsole(uploadDetails: UploadDetails): void {
|
private _logUploadDetailsInConsole(uploadDetails: UploadDetails): void {
|
||||||
|
@ -41,9 +41,9 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
|
|||||||
this.isCollectionExpanded = ko.observable<boolean>(true);
|
this.isCollectionExpanded = ko.observable<boolean>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public expandCollection(): Q.Promise<void> {
|
public expandCollection(): void {
|
||||||
if (this.isCollectionExpanded()) {
|
if (this.isCollectionExpanded()) {
|
||||||
return Q();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isCollectionExpanded(true);
|
this.isCollectionExpanded(true);
|
||||||
@ -55,8 +55,6 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
|
|||||||
defaultExperience: this.container.defaultExperience(),
|
defaultExperience: this.container.defaultExperience(),
|
||||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||||
});
|
});
|
||||||
|
|
||||||
return Q.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public collapseCollection() {
|
public collapseCollection() {
|
||||||
|
@ -288,11 +288,9 @@ export class TabRouteHandler {
|
|||||||
private _openSprocTabForResource(databaseId: string, collectionId: string, sprocId: string): void {
|
private _openSprocTabForResource(databaseId: string, collectionId: string, sprocId: string): void {
|
||||||
this._executeActionHelper(() => {
|
this._executeActionHelper(() => {
|
||||||
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
||||||
collection &&
|
collection && collection.expandCollection();
|
||||||
collection.expandCollection().then(() => {
|
const storedProcedure = collection && collection.findStoredProcedureWithId(sprocId);
|
||||||
const storedProcedure = collection && collection.findStoredProcedureWithId(sprocId);
|
storedProcedure && storedProcedure.open();
|
||||||
storedProcedure && storedProcedure.open();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,11 +317,9 @@ export class TabRouteHandler {
|
|||||||
private _openTriggerTabForResource(databaseId: string, collectionId: string, triggerId: string): void {
|
private _openTriggerTabForResource(databaseId: string, collectionId: string, triggerId: string): void {
|
||||||
this._executeActionHelper(() => {
|
this._executeActionHelper(() => {
|
||||||
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
||||||
collection &&
|
collection && collection.expandCollection();
|
||||||
collection.expandCollection().then(() => {
|
const trigger = collection && collection.findTriggerWithId(triggerId);
|
||||||
const trigger = collection && collection.findTriggerWithId(triggerId);
|
trigger && trigger.open();
|
||||||
trigger && trigger.open();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,11 +346,9 @@ export class TabRouteHandler {
|
|||||||
private _openUserDefinedFunctionTabForResource(databaseId: string, collectionId: string, udfId: string): void {
|
private _openUserDefinedFunctionTabForResource(databaseId: string, collectionId: string, udfId: string): void {
|
||||||
this._executeActionHelper(() => {
|
this._executeActionHelper(() => {
|
||||||
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
const collection: ViewModels.Collection = this._findMatchingCollectionForResource(databaseId, collectionId);
|
||||||
collection &&
|
collection && collection.expandCollection();
|
||||||
collection.expandCollection().then(() => {
|
const userDefinedFunction = collection && collection.findUserDefinedFunctionWithId(udfId);
|
||||||
const userDefinedFunction = collection && collection.findUserDefinedFunctionWithId(udfId);
|
userDefinedFunction && userDefinedFunction.open();
|
||||||
userDefinedFunction && userDefinedFunction.open();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user