Feat/model backed ui (#1145)

This is an initial PR for a new model-driven UI where extensions can provide definitions of the components & how they're laid out using Containers.
#1140, #1141, #1142, #1143 and #1144 are all tracking additional work needed to improve the initial implementation and fix some issues with the implementation.

Features:
- Supports defining a FlexContainer that maps to a flexbox-based layout.
- Supports creating a card component, which is a key-value pair based control that will lay out simple information to a user. Eventually this will have an optional set of actions associated with it.
- Has a sample project which shows how to use the API and was used for verification
This commit is contained in:
Kevin Cunnane
2018-04-13 15:59:18 -07:00
committed by GitHub
parent e022f4a0d1
commit b2c70e9301
63 changed files with 13238 additions and 84 deletions

View File

@@ -0,0 +1,89 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Registry } from 'vs/platform/registry/common/platform';
import * as sqlops from 'sqlops';
import { IModelStore, IComponentDescriptor, IComponent } from './interfaces';
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
import { Deferred } from 'sql/base/common/promise';
const componentRegistry = <IComponentRegistry> Registry.as(Extensions.ComponentContribution);
class ComponentDescriptor implements IComponentDescriptor {
constructor(public readonly id: string, public readonly type: string) {
}
}
export class ModelStore implements IModelStore {
private static baseId = 0;
private _descriptorMappings: { [x: string]: IComponentDescriptor } = {};
private _componentMappings: { [x: string]: IComponent } = {};
private _componentActions: { [x: string]: Deferred<IComponent> } = {};
constructor() {
}
public createComponentDescriptor(type: string, id: string): IComponentDescriptor {
let descriptor = new ComponentDescriptor(id, type);
this._descriptorMappings[id] = descriptor;
return descriptor;
}
getComponentDescriptor(id: string): IComponentDescriptor {
return this._descriptorMappings[id];
}
registerComponent(component: IComponent): void {
let id = component.descriptor.id;
this._componentMappings[id] = component;
this.runPendingActions(id, component);
}
unregisterComponent(component: IComponent): void {
let id = component.descriptor.id;
this._componentMappings[id] = undefined;
this._componentActions[id] = undefined;
// TODO notify model for cleanup
}
getComponent(componentId: string): IComponent {
return this._componentMappings[componentId];
}
eventuallyRunOnComponent<T>(componentId: string, action: (component: IComponent) => T): Promise<T> {
let component = this.getComponent(componentId);
if (component) {
return Promise.resolve(action(component));
} else {
return this.addPendingAction(componentId, action);
}
}
private addPendingAction<T>(componentId: string, action: (component: IComponent) => T): Promise<T> {
// We create a promise and chain it onto a tracking promise whose resolve method
// will only be called once the component is created
let deferredPromise = this._componentActions[componentId];
if (!deferredPromise) {
deferredPromise = new Deferred();
this._componentActions[componentId] = deferredPromise;
}
let promise = deferredPromise.promise.then((component) => {
return action(component);
});
return promise;
}
private runPendingActions(componentId: string, component: IComponent) {
let promiseTracker = this._componentActions[componentId];
if (promiseTracker) {
promiseTracker.resolve(component);
}
}
}