mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-10 10:12:34 -05:00
added Declarative table to model view controls (#1593)
* added Declarative table to model view controls
This commit is contained in:
@@ -30,6 +30,7 @@ export class InputBox extends AngularDisposable implements OnInit, OnChanges {
|
||||
@Input() type: string;
|
||||
@Input() placeholder: string;
|
||||
@Input() ariaLabel: string;
|
||||
@Input() value: string;
|
||||
|
||||
@Output() onDidChange = new EventEmitter<string | number>();
|
||||
|
||||
@@ -49,6 +50,9 @@ export class InputBox extends AngularDisposable implements OnInit, OnChanges {
|
||||
placeholder: this.placeholder,
|
||||
ariaLabel: this.ariaLabel
|
||||
});
|
||||
if (this.value) {
|
||||
this._inputbox.value = this.value;
|
||||
}
|
||||
this._inputbox.onDidChange(e => {
|
||||
switch (this.type) {
|
||||
case 'number':
|
||||
|
||||
@@ -52,11 +52,16 @@ import { DashboardControlHostContainer } from 'sql/parts/dashboard/containers/da
|
||||
import { JobsViewComponent } from 'sql/parts/jobManagement/views/jobsView.component';
|
||||
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
|
||||
import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
|
||||
|
||||
let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer,
|
||||
DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, ModelViewContent, WebviewContent, WidgetContent,
|
||||
ComponentHostDirective, BreadcrumbComponent, ControlHostContent, DashboardControlHostContainer,
|
||||
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent, DashboardModelViewContainer, ModelComponentWrapper];
|
||||
JobsViewComponent, AgentViewComponent, JobHistoryComponent, JobStepsViewComponent, DashboardModelViewContainer, ModelComponentWrapper, Checkbox,
|
||||
SelectBox,
|
||||
InputBox,];
|
||||
|
||||
/* Panel */
|
||||
import { PanelModule } from 'sql/base/browser/ui/panel/panel.module';
|
||||
|
||||
@@ -112,6 +112,14 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
||||
this.setProperties(properties);
|
||||
}
|
||||
|
||||
protected convertSize(size: number | string): string {
|
||||
let convertedSize: string = size ? size.toString() : '100%';
|
||||
if (!convertedSize.toLowerCase().endsWith('px') && !convertedSize.toLowerCase().endsWith('%')) {
|
||||
convertedSize = convertedSize + 'px';
|
||||
}
|
||||
return convertedSize;
|
||||
}
|
||||
|
||||
public get valid(): boolean {
|
||||
return this._valid;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import GroupContainer from './groupContainer.component';
|
||||
import CardComponent from './card.component';
|
||||
import InputBoxComponent from './inputbox.component';
|
||||
import DropDownComponent from './dropdown.component';
|
||||
import DeclarativeTableComponent from './declarativeTable.component';
|
||||
import ListBoxComponent from './listbox.component';
|
||||
import ButtonComponent from './button.component';
|
||||
import CheckBoxComponent from './checkbox.component';
|
||||
@@ -42,6 +43,9 @@ registerComponentType(INPUTBOX_COMPONENT, ModelComponentTypes.InputBox, InputBox
|
||||
export const DROPDOWN_COMPONENT = 'dropdown-component';
|
||||
registerComponentType(DROPDOWN_COMPONENT, ModelComponentTypes.DropDown, DropDownComponent);
|
||||
|
||||
export const DECLARATIVETABLE_COMPONENT = 'declarativeTable-component';
|
||||
registerComponentType(DECLARATIVETABLE_COMPONENT, ModelComponentTypes.DeclarativeTable, DeclarativeTableComponent);
|
||||
|
||||
export const LISTBOX_COMPONENT = 'lisbox-component';
|
||||
registerComponentType(LISTBOX_COMPONENT, ModelComponentTypes.ListBox, ListBoxComponent);
|
||||
|
||||
|
||||
194
src/sql/parts/modelComponents/declarativeTable.component.ts
Normal file
194
src/sql/parts/modelComponents/declarativeTable.component.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./declarativeTable';
|
||||
import {
|
||||
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit
|
||||
} from '@angular/core';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||
import { ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
string = 'string',
|
||||
category = 'category',
|
||||
boolean = 'boolean'
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'modelview-declarativeTable',
|
||||
template: `
|
||||
<table role=grid aria-labelledby="ID_REF" #container *ngIf="columns" class="declarative-table">
|
||||
<ng-container *ngFor="let column of columns;let h = index">
|
||||
<th class="declarative-table-header" tabindex="-1" role="button" aria-sort="none">{{column.displayName}}</th>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="data">
|
||||
<ng-container *ngFor="let row of data;let r = index">
|
||||
<tr class="declarative-table-row">
|
||||
<ng-container *ngFor="let cellData of row;let c = index">
|
||||
<td class="declarative-table-cell" tabindex="-1" role="button" [style.width]="getColumnWidth(c)">
|
||||
<checkbox *ngIf="isCheckBox(c)" label="" (onChange)="onCheckBoxChanged($event,r,c)" [enabled]="isControlEnabled(c)" [checked]="isChecked(r,c)"></checkbox>
|
||||
<select-box *ngIf="isSelectBox(c)" [options]="GetOptions(c)" (onDidSelect)="onSelectBoxChanged($event,r,c)" [selectedOption]="GetSelectedOptionDisplayName(r,c)"></select-box>
|
||||
<input-box *ngIf="isInputBox(c)" [value]="cellData" (onDidChange)="onInputBoxChanged($event,r,c)"></input-box>
|
||||
<ng-container *ngIf="isLabel(c)" >{{cellData}}</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</table>
|
||||
`
|
||||
})
|
||||
export default class DeclarativeTableComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||
@Input() descriptor: IComponentDescriptor;
|
||||
@Input() modelStore: IModelStore;
|
||||
|
||||
@ViewChild('container', { read: ElementRef }) private _tableContainer: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IContextViewService) private contextViewService: IContextViewService
|
||||
) {
|
||||
super(changeRef);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.baseInit();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
}
|
||||
|
||||
public validate(): Thenable<boolean> {
|
||||
return super.validate().then(valid => {
|
||||
return valid;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.baseDestroy();
|
||||
}
|
||||
|
||||
private isCheckBox(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.valueType === DeclarativeDataType.boolean;
|
||||
}
|
||||
|
||||
private isControlEnabled(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return !column.isReadOnly;
|
||||
}
|
||||
|
||||
private isLabel(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.isReadOnly && column.valueType === DeclarativeDataType.string;
|
||||
}
|
||||
|
||||
private isChecked(row: number, cell: number): boolean {
|
||||
let cellData = this.data[row][cell];
|
||||
return cellData;
|
||||
}
|
||||
|
||||
private onInputBoxChanged(e: string, row: number, cell: number): void {
|
||||
this.onCellDataChanged(e, row, cell);
|
||||
}
|
||||
|
||||
private onCheckBoxChanged(e: boolean, row: number, cell: number): void {
|
||||
this.onCellDataChanged(e, row, cell);
|
||||
}
|
||||
|
||||
private onSelectBoxChanged(e: ISelectData, row: number, cell: number): void {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
if (column.categoryValues) {
|
||||
this.onCellDataChanged(column.categoryValues[e.index].name, row, cell);
|
||||
}
|
||||
}
|
||||
|
||||
private onCellDataChanged(newValue: any, row: number, cell: number): void {
|
||||
this.data[row][cell] = newValue;
|
||||
this.data = this.data;
|
||||
let newCellData : sqlops.TableCell = {
|
||||
row: row,
|
||||
column: cell,
|
||||
value: newValue
|
||||
};
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidChange,
|
||||
args: newCellData
|
||||
});
|
||||
}
|
||||
|
||||
private isSelectBox(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.valueType === DeclarativeDataType.category;
|
||||
}
|
||||
|
||||
private isInputBox(cell: number): boolean {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.valueType === DeclarativeDataType.string && !column.isReadOnly;
|
||||
}
|
||||
|
||||
private getColumnWidth(cell: number): string {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return this.convertSize(column.width);
|
||||
}
|
||||
|
||||
private GetOptions(cell: number): string[] {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
return column.categoryValues ? column.categoryValues.map(x => x.displayName) : [];
|
||||
}
|
||||
|
||||
private GetSelectedOptionDisplayName(row: number, cell: number): string {
|
||||
let column: sqlops.DeclarativeTableColumn = this.columns[cell];
|
||||
let cellData = this.data[row][cell];
|
||||
if (cellData && column.categoryValues) {
|
||||
let category = column.categoryValues.find(v => v.name === cellData);
|
||||
return category.displayName;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
}
|
||||
|
||||
public setProperties(properties: { [key: string]: any; }): void {
|
||||
super.setProperties(properties);
|
||||
}
|
||||
|
||||
public get data(): any[][] {
|
||||
return this.getPropertyOrDefault<sqlops.DeclarativeTableProperties, any[]>((props) => props.data, []);
|
||||
}
|
||||
|
||||
public set data(newValue: any[][]) {
|
||||
this.setPropertyFromUI<sqlops.DeclarativeTableProperties, any[][]>((props, value) => props.data = value, newValue);
|
||||
}
|
||||
|
||||
public get columns(): sqlops.DeclarativeTableColumn[] {
|
||||
return this.getPropertyOrDefault<sqlops.DeclarativeTableProperties, sqlops.DeclarativeTableColumn[]>((props) => props.columns, []);
|
||||
}
|
||||
|
||||
public set columns(newValue: sqlops.DeclarativeTableColumn[]) {
|
||||
this.setPropertyFromUI<sqlops.DeclarativeTableProperties, sqlops.DeclarativeTableColumn[]>((props, value) => props.columns = value, newValue);
|
||||
}
|
||||
}
|
||||
41
src/sql/parts/modelComponents/declarativeTable.css
Normal file
41
src/sql/parts/modelComponents/declarativeTable.css
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
.declarative-table {
|
||||
padding: 5px 30px 0px 30px;
|
||||
box-sizing: border-box;
|
||||
width:100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.declarative-table-row {
|
||||
}
|
||||
|
||||
.declarative-table-header {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.vs-dark .declarative-table-header {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
background-color: #333334;
|
||||
}
|
||||
|
||||
.hc-black .declarative-table-header {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
background-color: #333334;
|
||||
}
|
||||
|
||||
.declarative-table-cell {
|
||||
padding: 5px;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
[role="gridcell"]:focus,
|
||||
[role="gridcell"] *:focus,
|
||||
[role="grid"] [tabindex="0"]:focus {
|
||||
outline: #005a9c;
|
||||
outline-style: dotted;
|
||||
outline-width: 3px;
|
||||
}
|
||||
@@ -19,6 +19,9 @@ import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
|
||||
|
||||
/* Model-backed components */
|
||||
let extensionComponents = Registry.as<IComponentRegistry>(Extensions.ComponentContribution).getAllCtors();
|
||||
@@ -26,6 +29,9 @@ let extensionComponents = Registry.as<IComponentRegistry>(Extensions.ComponentCo
|
||||
export const DialogModule = (params, selector: string): any => {
|
||||
@NgModule({
|
||||
declarations: [
|
||||
Checkbox,
|
||||
SelectBox,
|
||||
InputBox,
|
||||
DialogContainer,
|
||||
ModelViewContent,
|
||||
ModelComponentWrapper,
|
||||
|
||||
31
src/sql/sqlops.proposed.d.ts
vendored
31
src/sql/sqlops.proposed.d.ts
vendored
@@ -28,6 +28,7 @@ declare module 'sqlops' {
|
||||
dropDown(): ComponentBuilder<DropDownComponent>;
|
||||
listBox(): ComponentBuilder<ListBoxComponent>;
|
||||
table(): ComponentBuilder<TableComponent>;
|
||||
declarativeTable(): ComponentBuilder<DeclarativeTableComponent>;
|
||||
dashboardWidget(widgetId: string): ComponentBuilder<DashboardWidgetComponent>;
|
||||
dashboardWebview(webviewId: string): ComponentBuilder<DashboardWebviewComponent>;
|
||||
formContainer(): FormBuilder;
|
||||
@@ -318,6 +319,12 @@ declare module 'sqlops' {
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
string = 'string',
|
||||
category = 'category',
|
||||
boolean = 'boolean'
|
||||
}
|
||||
|
||||
export interface RadioButtonProperties {
|
||||
name?: string;
|
||||
label?: string;
|
||||
@@ -335,9 +342,23 @@ declare module 'sqlops' {
|
||||
editable?: boolean;
|
||||
}
|
||||
|
||||
export interface DeclarativeTableColumn {
|
||||
displayName: string;
|
||||
categoryValues: CategoryValue[];
|
||||
valueType: DeclarativeDataType;
|
||||
isReadOnly: boolean;
|
||||
width: number|string;
|
||||
}
|
||||
|
||||
export interface DeclarativeTableProperties {
|
||||
data: any[][];
|
||||
columns: DeclarativeTableColumn[];
|
||||
}
|
||||
|
||||
export interface ListBoxProperties {
|
||||
selectedRow?: number;
|
||||
values?: string[];
|
||||
|
||||
}
|
||||
|
||||
export interface WebViewProperties {
|
||||
@@ -385,6 +406,16 @@ declare module 'sqlops' {
|
||||
onValueChanged: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface TableCell {
|
||||
row: number;
|
||||
column: number;
|
||||
value: any;
|
||||
}
|
||||
|
||||
export interface DeclarativeTableComponent extends Component, DeclarativeTableProperties {
|
||||
onDataChanged: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface ListBoxComponent extends Component, ListBoxProperties {
|
||||
selectedRow?: number;
|
||||
values: string[];
|
||||
|
||||
@@ -69,6 +69,7 @@ export enum ModelComponentTypes {
|
||||
Card,
|
||||
InputBox,
|
||||
DropDown,
|
||||
DeclarativeTable,
|
||||
ListBox,
|
||||
Button,
|
||||
CheckBox,
|
||||
@@ -186,3 +187,9 @@ export enum DataProviderType {
|
||||
AgentServicesProvider = 'AgentServicesProvider',
|
||||
CapabilitiesProvider = 'CapabilitiesProvider'
|
||||
}
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
string = 'string',
|
||||
category = 'category',
|
||||
boolean = 'boolean'
|
||||
}
|
||||
@@ -130,6 +130,13 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
||||
return builder;
|
||||
}
|
||||
|
||||
declarativeTable(): sqlops.ComponentBuilder<sqlops.DeclarativeTableComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder: ComponentBuilderImpl<sqlops.DeclarativeTableComponent> = this.getComponentBuilder(new DeclarativeTableWrapper(this._proxy, this._handle, id), id);
|
||||
this._componentBuilders.set(id, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
dashboardWidget(widgetId: string): sqlops.ComponentBuilder<sqlops.DashboardWidgetComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder = this.getComponentBuilder<sqlops.DashboardWidgetComponent>(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWidget, id), id);
|
||||
@@ -755,6 +762,35 @@ class DropDownWrapper extends ComponentWrapper implements sqlops.DropDownCompone
|
||||
}
|
||||
}
|
||||
|
||||
class DeclarativeTableWrapper extends ComponentWrapper implements sqlops.DeclarativeTableComponent {
|
||||
|
||||
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||
super(proxy, handle, ModelComponentTypes.DeclarativeTable, id);
|
||||
this.properties = {};
|
||||
this._emitterMap.set(ComponentEventType.onDidChange, new Emitter<any>());
|
||||
}
|
||||
|
||||
public get data(): any[][] {
|
||||
return this.properties['data'];
|
||||
}
|
||||
public set data(v: any[][]) {
|
||||
this.setProperty('data', v);
|
||||
}
|
||||
|
||||
public get columns(): sqlops.DeclarativeTableColumn[] {
|
||||
return this.properties['columns'];
|
||||
}
|
||||
|
||||
public set columns(v: sqlops.DeclarativeTableColumn[]) {
|
||||
this.setProperty('columns', v);
|
||||
}
|
||||
|
||||
public get onDataChanged(): vscode.Event<any> {
|
||||
let emitter = this._emitterMap.get(ComponentEventType.onDidChange);
|
||||
return emitter && emitter.event;
|
||||
}
|
||||
}
|
||||
|
||||
class ListBoxWrapper extends ComponentWrapper implements sqlops.ListBoxComponent {
|
||||
|
||||
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||
|
||||
@@ -369,6 +369,7 @@ export function createApiFactory(
|
||||
serialization,
|
||||
dataprotocol,
|
||||
DataProviderType: sqlExtHostTypes.DataProviderType,
|
||||
DeclarativeDataType: sqlExtHostTypes.DeclarativeDataType,
|
||||
ServiceOptionType: sqlExtHostTypes.ServiceOptionType,
|
||||
ConnectionOptionSpecialType: sqlExtHostTypes.ConnectionOptionSpecialType,
|
||||
EditRowState: sqlExtHostTypes.EditRowState,
|
||||
|
||||
Reference in New Issue
Block a user