mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Do ModelView initialization actions before others (#11512)
This commit is contained in:
@@ -67,8 +67,9 @@ export interface IModelStore {
|
|||||||
*
|
*
|
||||||
* @param componentId unique identifier of the component
|
* @param componentId unique identifier of the component
|
||||||
* @param action some action to perform
|
* @param action some action to perform
|
||||||
|
* @param isInitialization whether this is an initialization action that will run before other actions
|
||||||
*/
|
*/
|
||||||
eventuallyRunOnComponent<T>(componentId: string, action: (component: IComponent) => T): Promise<T>;
|
eventuallyRunOnComponent<T>(componentId: string, action: (component: IComponent) => T, isInitialization?: boolean): Promise<T>;
|
||||||
/**
|
/**
|
||||||
* Register a callback that will validate components when given a component ID
|
* Register a callback that will validate components when given a component ID
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export class ModelStore implements IModelStore {
|
|||||||
private _descriptorMappings: { [x: string]: IComponentDescriptor } = {};
|
private _descriptorMappings: { [x: string]: IComponentDescriptor } = {};
|
||||||
private _componentMappings: { [x: string]: IComponent } = {};
|
private _componentMappings: { [x: string]: IComponent } = {};
|
||||||
private _componentActions: { [x: string]: Deferred<IComponent> } = {};
|
private _componentActions: { [x: string]: Deferred<IComponent> } = {};
|
||||||
|
private _componentInitializationActions: { [x: string]: Deferred<IComponent> } = {};
|
||||||
private _validationCallbacks: ((componentId: string) => Thenable<boolean>)[] = [];
|
private _validationCallbacks: ((componentId: string) => Thenable<boolean>)[] = [];
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
@@ -51,12 +52,12 @@ export class ModelStore implements IModelStore {
|
|||||||
return this._componentMappings[componentId];
|
return this._componentMappings[componentId];
|
||||||
}
|
}
|
||||||
|
|
||||||
eventuallyRunOnComponent<T>(componentId: string, action: (component: IComponent) => T): Promise<T> {
|
eventuallyRunOnComponent<T>(componentId: string, action: (component: IComponent) => T, isInitialization: boolean = false): Promise<T> {
|
||||||
let component = this.getComponent(componentId);
|
let component = this.getComponent(componentId);
|
||||||
if (component) {
|
if (component) {
|
||||||
return Promise.resolve(action(component));
|
return Promise.resolve(action(component));
|
||||||
} else {
|
} else {
|
||||||
return this.addPendingAction(componentId, action);
|
return this.addPendingAction(componentId, action, isInitialization);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,13 +70,18 @@ export class ModelStore implements IModelStore {
|
|||||||
return Promise.all(this._validationCallbacks.map(callback => callback(componentId))).then(validations => validations.every(validation => validation === true));
|
return Promise.all(this._validationCallbacks.map(callback => callback(componentId))).then(validations => validations.every(validation => validation === true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private addPendingAction<T>(componentId: string, action: (component: IComponent) => T): Promise<T> {
|
private addPendingAction<T>(componentId: string, action: (component: IComponent) => T, isInitialization: boolean): Promise<T> {
|
||||||
// We create a promise and chain it onto a tracking promise whose resolve method
|
// We create a promise and chain it onto a tracking promise whose resolve method
|
||||||
// will only be called once the component is created
|
// will only be called once the component is created
|
||||||
let deferredPromise = this._componentActions[componentId];
|
|
||||||
|
// If this is an initialization action we want to run it before the other actions that may have come in
|
||||||
|
// after initialization but before the component was finished being created or we hit race conditions with
|
||||||
|
// setting properties
|
||||||
|
const actionsStore = isInitialization ? this._componentInitializationActions : this._componentActions;
|
||||||
|
let deferredPromise = actionsStore[componentId];
|
||||||
if (!deferredPromise) {
|
if (!deferredPromise) {
|
||||||
deferredPromise = new Deferred();
|
deferredPromise = new Deferred();
|
||||||
this._componentActions[componentId] = deferredPromise;
|
actionsStore[componentId] = deferredPromise;
|
||||||
}
|
}
|
||||||
let promise = deferredPromise.promise.then((component) => {
|
let promise = deferredPromise.promise.then((component) => {
|
||||||
return action(component);
|
return action(component);
|
||||||
@@ -84,9 +90,10 @@ export class ModelStore implements IModelStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private runPendingActions(componentId: string, component: IComponent) {
|
private runPendingActions(componentId: string, component: IComponent) {
|
||||||
let promiseTracker = this._componentActions[componentId];
|
// If we have initialization actions to run start those first
|
||||||
if (promiseTracker) {
|
const initializationActionsPromise = this._componentInitializationActions[componentId];
|
||||||
promiseTracker.resolve(component);
|
initializationActionsPromise?.resolve(component);
|
||||||
}
|
const actionsPromise = this._componentActions[componentId];
|
||||||
|
actionsPromise?.resolve(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,12 +58,12 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
throw new Error(nls.localize('componentTypeNotRegistered', "Could not find component for type {0}", ModelComponentTypes[component.type]));
|
throw new Error(nls.localize('componentTypeNotRegistered', "Could not find component for type {0}", ModelComponentTypes[component.type]));
|
||||||
}
|
}
|
||||||
let descriptor = this.modelStore.createComponentDescriptor(typeId, component.id);
|
let descriptor = this.modelStore.createComponentDescriptor(typeId, component.id);
|
||||||
this.setProperties(component.id, component.properties);
|
this.setProperties(component.id, component.properties, true);
|
||||||
this.setLayout(component.id, component.layout);
|
this.setLayout(component.id, component.layout, true);
|
||||||
this.registerEvent(component.id);
|
this.registerEvent(component.id, true);
|
||||||
if (component.itemConfigs) {
|
if (component.itemConfigs) {
|
||||||
for (let item of component.itemConfigs) {
|
for (let item of component.itemConfigs) {
|
||||||
this.addToContainer(component.id, item);
|
this.addToContainer(component.id, item, undefined, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,12 +82,12 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
this.queueAction(componentId, (component) => component.clearContainer());
|
this.queueAction(componentId, (component) => component.clearContainer());
|
||||||
}
|
}
|
||||||
|
|
||||||
addToContainer(containerId: string, itemConfig: IItemConfig, index?: number): void {
|
addToContainer(containerId: string, itemConfig: IItemConfig, index?: number, isInitialization?: boolean): void {
|
||||||
// Do not return the promise as this should be non-blocking
|
// Do not return the promise as this should be non-blocking
|
||||||
this.queueAction(containerId, (component) => {
|
this.queueAction(containerId, (component) => {
|
||||||
let childDescriptor = this.defineComponent(itemConfig.componentShape);
|
let childDescriptor = this.defineComponent(itemConfig.componentShape);
|
||||||
component.addToContainer(childDescriptor, itemConfig.config, index);
|
component.addToContainer(childDescriptor, itemConfig.config, index);
|
||||||
});
|
}, isInitialization);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFromContainer(containerId: string, itemConfig: IItemConfig): void {
|
removeFromContainer(containerId: string, itemConfig: IItemConfig): void {
|
||||||
@@ -98,11 +98,11 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setLayout(componentId: string, layout: any): void {
|
setLayout(componentId: string, layout: any, isInitialization?: boolean): void {
|
||||||
if (!layout) {
|
if (!layout) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.queueAction(componentId, (component) => component.setLayout(layout));
|
this.queueAction(componentId, (component) => component.setLayout(layout), isInitialization);
|
||||||
}
|
}
|
||||||
|
|
||||||
setItemLayout(containerId: string, itemConfig: IItemConfig): void {
|
setItemLayout(containerId: string, itemConfig: IItemConfig): void {
|
||||||
@@ -112,24 +112,24 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setProperties(componentId: string, properties: { [key: string]: any; }): void {
|
setProperties(componentId: string, properties: { [key: string]: any; }, isInitialization?: boolean): void {
|
||||||
if (!properties) {
|
if (!properties) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.queueAction(componentId, (component) => component.setProperties(properties));
|
this.queueAction(componentId, (component) => component.setProperties(properties), isInitialization);
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshDataProvider(componentId: string, item: any): void {
|
refreshDataProvider(componentId: string, item: any): void {
|
||||||
this.queueAction(componentId, (component) => component.refreshDataProvider(item));
|
this.queueAction(componentId, (component) => component.refreshDataProvider(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
private queueAction<T>(componentId: string, action: (component: IComponent) => T): void {
|
private queueAction<T>(componentId: string, action: (component: IComponent) => T, isInitialization?: boolean): void {
|
||||||
this.modelStore.eventuallyRunOnComponent(componentId, action).catch(err => {
|
this.modelStore.eventuallyRunOnComponent(componentId, action, isInitialization).catch(err => {
|
||||||
// TODO add error handling
|
// TODO add error handling
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
registerEvent(componentId: string) {
|
registerEvent(componentId: string, isInitialization?: boolean) {
|
||||||
this.queueAction(componentId, (component) => {
|
this.queueAction(componentId, (component) => {
|
||||||
this._register(component.registerEventHandler(e => {
|
this._register(component.registerEventHandler(e => {
|
||||||
let modelViewEvent: IModelViewEventArgs = assign({
|
let modelViewEvent: IModelViewEventArgs = assign({
|
||||||
@@ -138,7 +138,7 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
}, e);
|
}, e);
|
||||||
this._onEventEmitter.fire(modelViewEvent);
|
this._onEventEmitter.fire(modelViewEvent);
|
||||||
}));
|
}));
|
||||||
});
|
}, isInitialization);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get onEvent(): Event<IModelViewEventArgs> {
|
public get onEvent(): Event<IModelViewEventArgs> {
|
||||||
|
|||||||
Reference in New Issue
Block a user