Add styling and component column type to declarative table (#8476)

* Initial wip

* wip

* Working implementation

* Make widths a bit nicer and remove sqlops addition

* Add sqlops back in

* Fix timing issue with tables

* Undo change to sql.bat and remove loading component when done
This commit is contained in:
Charles Gagnon
2019-11-27 08:06:41 -08:00
committed by GitHub
parent 0e9797c394
commit 3135b8525b
12 changed files with 648 additions and 333 deletions

View File

@@ -21,7 +21,8 @@ export enum DeclarativeDataType {
string = 'string',
category = 'category',
boolean = 'boolean',
editableCategory = 'editableCategory'
editableCategory = 'editableCategory',
component = 'component'
}
@Component({
@@ -29,20 +30,21 @@ export enum DeclarativeDataType {
template: `
<table role=grid #container *ngIf="columns" class="declarative-table" [style.height]="getHeight()" [attr.aria-label]="ariaLabel">
<thead>
<ng-container *ngFor="let column of columns;let h = index">
<th class="declarative-table-header" tabindex="-1" aria-sort="none">{{column.displayName}}</th>
<ng-container *ngFor="let column of columns;">
<th class="declarative-table-header" tabindex="-1" aria-sort="none" [ngStyle]="column.headerCssStyles">{{column.displayName}}</th>
</ng-container>
</thead>
<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" [style.width]="getColumnWidth(c)" [attr.aria-label]="getAriaLabel(r, c)" >
<td class="declarative-table-cell" tabindex="-1" [style.width]="getColumnWidth(c)" [attr.aria-label]="getAriaLabel(r, c)" [ngStyle]="columns[c].rowCssStyles">
<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>
<editable-select-box *ngIf="isEditableSelectBox(c)" [options]="getOptions(c)" (onDidSelect)="onSelectBoxChanged($event,r,c)" [selectedOption]="getSelectedOptionDisplayName(r,c)"></editable-select-box>
<input-box *ngIf="isInputBox(c)" [value]="cellData" (onDidChange)="onInputBoxChanged($event,r,c)"></input-box>
<ng-container *ngIf="isLabel(c)" >{{cellData}}</ng-container>
<model-component-wrapper *ngIf="isComponent(c)" [descriptor]="getItemDescriptor(cellData)" [modelStore]="modelStore"></model-component-wrapper>
</td>
</ng-container>
</tr>
@@ -79,57 +81,57 @@ export default class DeclarativeTableComponent extends ComponentBase implements
this.baseDestroy();
}
public isCheckBox(cell: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
public isCheckBox(colIdx: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return column.valueType === DeclarativeDataType.boolean;
}
public isControlEnabled(cell: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
public isControlEnabled(colIdx: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return !column.isReadOnly;
}
private isLabel(cell: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
private isLabel(colIdx: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return column.isReadOnly && column.valueType === DeclarativeDataType.string;
}
public isChecked(row: number, cell: number): boolean {
let cellData = this.data[row][cell];
public isChecked(rowIdx: number, colIdx: number): boolean {
let cellData = this.data[rowIdx][colIdx];
return cellData;
}
public onInputBoxChanged(e: string, row: number, cell: number): void {
this.onCellDataChanged(e, row, cell);
public onInputBoxChanged(e: string, rowIdx: number, colIdx: number): void {
this.onCellDataChanged(e, rowIdx, colIdx);
}
public onCheckBoxChanged(e: boolean, row: number, cell: number): void {
this.onCellDataChanged(e, row, cell);
public onCheckBoxChanged(e: boolean, rowIdx: number, colIdx: number): void {
this.onCellDataChanged(e, rowIdx, colIdx);
}
public onSelectBoxChanged(e: ISelectData | string, row: number, cell: number): void {
public onSelectBoxChanged(e: ISelectData | string, rowIdx: number, colIdx: number): void {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
if (column.categoryValues) {
if (typeof e === 'string') {
let category = find(column.categoryValues, c => c.displayName === e);
if (category) {
this.onCellDataChanged(category.name, row, cell);
this.onCellDataChanged(category.name, rowIdx, colIdx);
} else {
this.onCellDataChanged(e, row, cell);
this.onCellDataChanged(e, rowIdx, colIdx);
}
} else {
this.onCellDataChanged(column.categoryValues[e.index].name, row, cell);
this.onCellDataChanged(column.categoryValues[e.index].name, rowIdx, colIdx);
}
}
}
private onCellDataChanged(newValue: any, row: number, cell: number): void {
this.data[row][cell] = newValue;
private onCellDataChanged(newValue: any, rowIdx: number, colIdx: number): void {
this.data[rowIdx][colIdx] = newValue;
this.data = this.data;
let newCellData: azdata.TableCell = {
row: row,
column: cell,
row: rowIdx,
column: colIdx,
value: newValue
};
this.fireEvent({
@@ -138,39 +140,43 @@ export default class DeclarativeTableComponent extends ComponentBase implements
});
}
public isSelectBox(cell: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
public isSelectBox(colIdx: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return column.valueType === DeclarativeDataType.category;
}
private isEditableSelectBox(cell: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
private isEditableSelectBox(colIdx: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return column.valueType === DeclarativeDataType.editableCategory;
}
public isInputBox(cell: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
public isInputBox(colIdx: number): boolean {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return column.valueType === DeclarativeDataType.string && !column.isReadOnly;
}
public getColumnWidth(cell: number): string {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
public isComponent(colIdx: number): boolean {
return this.columns[colIdx].valueType === DeclarativeDataType.component;
}
public getColumnWidth(colIdx: number): string {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return this.convertSize(column.width, '30px');
}
public getOptions(cell: number): string[] {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
public getOptions(colIdx: number): string[] {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
return column.categoryValues ? column.categoryValues.map(x => x.displayName) : [];
}
public getSelectedOptionDisplayName(row: number, cell: number): string {
let column: azdata.DeclarativeTableColumn = this.columns[cell];
let cellData = this.data[row][cell];
public getSelectedOptionDisplayName(rowIdx: number, colIdx: number): string {
let column: azdata.DeclarativeTableColumn = this.columns[colIdx];
let cellData = this.data[rowIdx][colIdx];
if (cellData && column.categoryValues) {
let category = find(column.categoryValues, v => v.name === cellData);
if (category) {
return category.displayName;
} else if (this.isEditableSelectBox(cell)) {
} else if (this.isEditableSelectBox(colIdx)) {
return cellData;
} else {
return undefined;
@@ -180,9 +186,13 @@ export default class DeclarativeTableComponent extends ComponentBase implements
}
}
public getAriaLabel(row: number, column: number): string {
const cellData = this.data[row][column];
return this.isLabel(column) ? (cellData && cellData !== '' ? cellData : localize('blankValue', "blank")) : '';
public getAriaLabel(rowIdx: number, colIdx: number): string {
const cellData = this.data[rowIdx][colIdx];
return this.isLabel(colIdx) ? (cellData && cellData !== '' ? cellData : localize('blankValue', "blank")) : '';
}
public getItemDescriptor(componentId: string): IComponentDescriptor {
return this.modelStore.getComponentDescriptor(componentId);
}
/// IComponent implementation
@@ -211,4 +221,18 @@ export default class DeclarativeTableComponent extends ComponentBase implements
public set columns(newValue: azdata.DeclarativeTableColumn[]) {
this.setPropertyFromUI<azdata.DeclarativeTableProperties, azdata.DeclarativeTableColumn[]>((props, value) => props.columns = value, newValue);
}
// IComponent container-related implementation
// This is needed for the component column type - in order to have the components in the cells registered we call addItem
// on the extension side to create and register the component with the ModelStore. That requires that these methods be implemented
// though which isn't done by default for non-Container components and so we just stub out the implementation here (we already have
// the component IDs in the data property so there's no need to store them here as well)
public addToContainer(componentDescriptor: IComponentDescriptor, config: any, index?: number): void {
this._changeRef.detectChanges();
}
public clearContainer(): void {
this._changeRef.detectChanges();
}
}