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

206
src/sql/sqlops.proposed.d.ts vendored Normal file
View File

@@ -0,0 +1,206 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// This is the place for API experiments and proposal.
import * as core from 'sqlops';
import * as vscode from 'vscode';
declare module 'sqlops' {
/**
* Supports defining a model that can be instantiated as a view in the UI
* @export
* @interface ModelBuilder
*/
export interface ModelBuilder {
navContainer(): ContainerBuilder<NavContainer, any, any>;
flexContainer(): FlexBuilder;
card(): ComponentBuilder<CardComponent>;
dashboardWidget(widgetId: string): ComponentBuilder<WidgetComponent>;
dashboardWebview(webviewId: string): ComponentBuilder<WebviewComponent>;
}
export interface ComponentBuilder<T extends Component> {
component(): T;
withProperties<U>(properties: U): ComponentBuilder<T>;
}
export interface ContainerBuilder<T extends Component, TLayout,TItemLayout> extends ComponentBuilder<T> {
withLayout(layout: TLayout): ContainerBuilder<T, TLayout, TItemLayout>;
withItems(components: Array<Component>, itemLayout ?: TItemLayout): ContainerBuilder<T, TLayout, TItemLayout>;
}
export interface FlexBuilder extends ContainerBuilder<FlexContainer, FlexLayout, FlexItemLayout> {
}
export interface Component {
readonly id: string;
/**
* Sends any updated properties of the component to the UI
*
* @returns {Thenable<boolean>} Thenable that completes once the update
* has been applied in the UI
* @memberof Component
*/
updateProperties(properties: { [key: string]: any }): Thenable<boolean>;
}
/**
* A component that contains other components
*/
export interface Container<TLayout,TItemLayout> extends Component {
/**
* A copy of the child items array. This cannot be added to directly -
* components must be created using the create methods instead
*/
readonly items: Component[];
/**
* Removes all child items from this container
*/
clearItems(): void;
/**
* Creates a collection of child components and adds them all to this container
*
* @param itemConfigs the definitions
* @param {*} [itemLayout] Optional layout for the child items
*/
addItems(itemConfigs: Array<Component>, itemLayout ?: TItemLayout): void;
/**
* Creates a child component and adds it to this container.
*
* @param {Component} component the component to be added
* @param {*} [itemLayout] Optional layout for this child item
*/
addItem(component: Component, itemLayout ?: TItemLayout): void;
/**
* Defines the layout for this container
*
* @param {TLayout} layout object
*/
setLayout(layout: TLayout): void;
}
export interface NavContainer extends Container<any, any> {
}
/**
* The config for a FlexBox-based container. This supports easy
* addition of content to a container with a flexible layout
* and use of space.
*/
export interface FlexLayout {
/**
* Matches the flex-flow CSS property and its available values.
* To layout as a vertical view use "column", and for horizontal
* use "row".
*/
flexFlow?: string;
/**
* Matches the justify-content CSS property.
*/
justifyContent?: string;
}
export interface FlexItemLayout {
/**
* Matches the order CSS property and its available values.
*/
order?: number;
/**
* Matches the flex CSS property and its available values.
* Default is "0 1 auto".
*/
flex?: string;
}
export interface FlexContainer extends Container<FlexLayout, FlexItemLayout> {
}
/**
* Describes an action to be shown in the UI, with a user-readable label
* and a callback to execute the action
*/
export interface ActionDescriptor {
/**
* User-visible label to display
*/
label: string;
/**
* ID of the task to be called when this is clicked on.
* These should be registered using the {tasks.registerTask} API.
*/
taskId: string;
}
/**
* Properties representing the card component, can be used
* when using ModelBuilder to create the comopnent
*/
export interface CardProperties {
label: string;
value?: string;
actions?: ActionDescriptor[];
}
export interface CardComponent extends Component {
label: string;
value: string;
actions?: ActionDescriptor[];
}
export interface WidgetComponent extends Component {
widgetId: string;
}
export interface WebviewComponent extends Component {
webviewId: string;
}
/**
* A view backed by a model provided by an extension.
* This model contains enough information to lay out the view
*/
export interface ModelView {
/**
* Raised when the view closed.
*/
readonly onClosed: vscode.Event<any>;
/**
* The connection info for the dashboard the webview exists on
*/
readonly connection: connection.Connection;
/**
* The info on the server for the dashboard
*/
readonly serverInfo: ServerInfo;
/**
* The model backing the model-based view
*/
readonly modelBuilder: ModelBuilder;
/**
* Initializes the model with a root component definition.
* Once this has been done, the components will be laid out in the UI and
* can be accessed and altered as needed.
*/
initializeModel<T extends Component>(root: T): Thenable<void>;
}
export namespace dashboard {
/**
* Register a provider for a model-view widget
*/
export function registerModelViewProvider(widgetId: string, handler: (view: ModelView) => void): void;
}
}