Form renderer enhancements (#1839)

- readonly mode for “Dynamic Table”
- “Display Value” now just uses “Dynamic Table” if needed (previously
rendered the table itself)
- support for “tableEditable” settings
This commit is contained in:
Denys Vuika
2017-04-24 11:51:42 +01:00
committed by Mario Romano
parent 95711616ca
commit 1dd283b0d8
6 changed files with 48 additions and 211 deletions

View File

@@ -42,30 +42,7 @@
</div> </div>
</div> </div>
<div *ngSwitchCase="'dynamic-table'"> <div *ngSwitchCase="'dynamic-table'">
<dynamic-table-widget [field]="field" [readOnly]="!tableEditable"></dynamic-table-widget>
<div class="display-value-widget__dynamic-table">
<div>{{field.name}}</div>
<div class="display-value-dynamic-table-widget__table-container">
<table class="mdl-data-table mdl-js-data-table">
<thead>
<tr>
<th *ngFor="let column of visibleColumns"
class="mdl-data-table__cell--non-numeric is-disabled">
{{column.name}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of rows">
<td *ngFor="let column of visibleColumns"
class="mdl-data-table__cell--non-numeric is-disabled">
{{ getCellValue(row, column) }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div> </div>
<div *ngSwitchCase="'upload'"> <div *ngSwitchCase="'upload'">
<div *ngIf="hasFile" class="mdl-grid"> <div *ngIf="hasFile" class="mdl-grid">

View File

@@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { CoreModule, LogServiceMock } from 'ng2-alfresco-core'; import { CoreModule, LogServiceMock } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
@@ -25,7 +26,6 @@ import { EcmModelService } from '../../../services/ecm-model.service';
import { FormFieldModel } from './../core/form-field.model'; import { FormFieldModel } from './../core/form-field.model';
import { FormFieldTypes } from '../core/form-field-types'; import { FormFieldTypes } from '../core/form-field-types';
import { FormModel } from '../core/form.model'; import { FormModel } from '../core/form.model';
import { DynamicTableColumn, DynamicTableRow } from './../dynamic-table/dynamic-table.widget.model';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service'; import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
describe('DisplayValueWidget', () => { describe('DisplayValueWidget', () => {
@@ -608,135 +608,6 @@ describe('DisplayValueWidget', () => {
expect(widget.value).toBe(value); expect(widget.value).toBe(value);
}); });
it('should setup [DYNAMIC_TABLE] field', () => {
let columns = [{id: '1', visible: false}, {id: '2', visible: true}];
let rows = [{}, {}];
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
params: {
field: {
type: FormFieldTypes.DYNAMIC_TABLE
}
},
columnDefinitions: columns,
value: rows
});
widget.ngOnInit();
expect(widget.columns.length).toBe(2);
expect(widget.columns[0].id).toBe(columns[0].id);
expect(widget.columns[1].id).toBe(columns[1].id);
expect(widget.visibleColumns.length).toBe(1);
expect(widget.visibleColumns[0].id).toBe(columns[1].id);
expect(widget.rows.length).toBe(2);
});
it('should setup [DYNAMIC_TABLE] field with empty schema', () => {
widget.field = new FormFieldModel(null, {
type: FormFieldTypes.DISPLAY_VALUE,
params: {
field: {
type: FormFieldTypes.DYNAMIC_TABLE
}
},
columnDefinitions: null,
value: null
});
widget.ngOnInit();
expect(widget.value).toBeNull();
expect(widget.columns).toEqual([]);
expect(widget.rows).toEqual([]);
});
it('should retrieve default cell value', () => {
const value = '<value>';
let row = <DynamicTableRow> {value: {key: value}};
let column = <DynamicTableColumn> {id: 'key'};
expect(widget.getCellValue(row, column)).toBe(value);
});
it('should retrieve dropdown cell value', () => {
const value = {id: '1', name: 'one'};
let row = <DynamicTableRow> {value: {key: value}};
let column = <DynamicTableColumn> {id: 'key', type: 'Dropdown'};
expect(widget.getCellValue(row, column)).toBe(value.name);
});
it('should fallback to empty cell value for dropdown', () => {
let row = <DynamicTableRow> {value: {}};
let column = <DynamicTableColumn> {id: 'key', type: 'Dropdown'};
expect(widget.getCellValue(row, column)).toBe('');
});
it('should retrieve boolean cell value', () => {
let row1 = <DynamicTableRow> {value: {key: true}};
let row2 = <DynamicTableRow> {value: {key: 'positive'}};
let row3 = <DynamicTableRow> {value: {key: null}};
let column = <DynamicTableColumn> {id: 'key', type: 'Boolean'};
expect(widget.getCellValue(row1, column)).toBe(true);
expect(widget.getCellValue(row2, column)).toBe(true);
expect(widget.getCellValue(row3, column)).toBe(false);
});
it('should retrieve date cell value', () => {
const value = '2016-10-04T00:00:00.000Z';
let row = <DynamicTableRow> {value: {key: value}};
let column = <DynamicTableColumn> {id: 'key', type: 'Date'};
expect(widget.getCellValue(row, column)).toBe('4-10-2016');
});
it('should fallback to empty cell value for date', () => {
let row = <DynamicTableRow> {value: {}};
let column = <DynamicTableColumn> {id: 'key', type: 'Date'};
expect(widget.getCellValue(row, column)).toBe('');
});
it('should retrieve empty text cell value', () => {
let row = <DynamicTableRow> {value: {}};
let column = <DynamicTableColumn> {id: 'key'};
expect(widget.getCellValue(row, column)).toBe('');
});
it('should prepend default amount currency', () => {
const value = '10';
let row = <DynamicTableRow> {value: {key: value}};
let column = <DynamicTableColumn> {id: 'key', type: 'Amount'};
const expected = `$ ${value}`;
expect(widget.getCellValue(row, column)).toBe(expected);
});
it('should prepend custom amount currency', () => {
const value = '10';
const currency = 'GBP';
let row = <DynamicTableRow> {value: {key: value}};
let column = <DynamicTableColumn> {id: 'key', type: 'Amount', amountCurrency: currency};
const expected = `${currency} ${value}`;
expect(widget.getCellValue(row, column)).toBe(expected);
});
it('should use zero for missing amount', () => {
const value = null;
const currency = 'GBP';
let row = <DynamicTableRow> {value: {key: value}};
let column = <DynamicTableColumn> {id: 'key', type: 'Amount', amountCurrency: currency};
const expected = `${currency} 0`;
expect(widget.getCellValue(row, column)).toBe(expected);
});
describe('UI check', () => { describe('UI check', () => {
let widgetUI: DisplayValueWidget; let widgetUI: DisplayValueWidget;
let fixture: ComponentFixture<DisplayValueWidget>; let fixture: ComponentFixture<DisplayValueWidget>;
@@ -748,12 +619,16 @@ describe('DisplayValueWidget', () => {
window['componentHandler'] = componentHandler; window['componentHandler'] = componentHandler;
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [CoreModule], imports: [CoreModule],
declarations: [DisplayValueWidget, ActivitiContent], declarations: [
DisplayValueWidget,
ActivitiContent
],
providers: [ providers: [
EcmModelService, EcmModelService,
FormService, FormService,
WidgetVisibilityService WidgetVisibilityService
] ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
}).compileComponents().then(() => { }).compileComponents().then(() => {
fixture = TestBed.createComponent(DisplayValueWidget); fixture = TestBed.createComponent(DisplayValueWidget);
widgetUI = fixture.componentInstance; widgetUI = fixture.componentInstance;

View File

@@ -22,7 +22,6 @@ import { WidgetComponent } from './../widget.component';
import { FormFieldTypes } from '../core/form-field-types'; import { FormFieldTypes } from '../core/form-field-types';
import { FormService } from '../../../services/form.service'; import { FormService } from '../../../services/form.service';
import { FormFieldOption } from './../core/form-field-option'; import { FormFieldOption } from './../core/form-field-option';
import { DynamicTableColumn, DynamicTableRow } from './../dynamic-table/dynamic-table.widget.model';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service'; import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
import { NumberFieldValidator } from '../core/form-field-validator'; import { NumberFieldValidator } from '../core/form-field-validator';
@@ -43,9 +42,7 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
linkText: string; linkText: string;
// dynamic table // dynamic table
rows: DynamicTableRow[] = []; tableEditable = false;
columns: DynamicTableColumn[] = [];
visibleColumns: DynamicTableColumn[] = [];
// upload/attach // upload/attach
hasFile: boolean = false; hasFile: boolean = false;
@@ -65,6 +62,10 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
if (this.field.params['showDocumentContent'] !== undefined) { if (this.field.params['showDocumentContent'] !== undefined) {
this.showDocumentContent = !!this.field.params['showDocumentContent']; this.showDocumentContent = !!this.field.params['showDocumentContent'];
} }
if (this.field.params['tableEditable'] !== undefined) {
this.tableEditable = !!this.field.params['tableEditable'];
}
let originalField = this.field.params['field']; let originalField = this.field.params['field'];
if (originalField && originalField.type) { if (originalField && originalField.type) {
this.fieldType = originalField.type; this.fieldType = originalField.type;
@@ -138,16 +139,6 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
this.linkUrl = this.getHyperlinkUrl(this.field); this.linkUrl = this.getHyperlinkUrl(this.field);
this.linkText = this.getHyperlinkText(this.field); this.linkText = this.getHyperlinkText(this.field);
break; break;
case FormFieldTypes.DYNAMIC_TABLE:
let json = this.field.json;
if (json.columnDefinitions) {
this.columns = json.columnDefinitions.map(obj => <DynamicTableColumn> obj);
this.visibleColumns = this.columns.filter(col => col.visible);
}
if (json.value) {
this.rows = json.value.map(obj => <DynamicTableRow> {selected: false, value: obj});
}
break;
default: default:
this.value = this.field.value; this.value = this.field.value;
break; break;
@@ -222,31 +213,4 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
} }
); );
} }
getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any {
let result = row.value[column.id];
if (column.type === 'Dropdown') {
if (result) {
return result.name;
}
}
if (column.type === 'Boolean') {
return result ? true : false;
}
if (column.type === 'Date') {
if (result) {
return moment(result.split('T')[0], 'YYYY-MM-DD').format('D-M-YYYY');
}
}
if (column.type === 'Amount') {
return (column.amountCurrency || '$') + ' ' + (result || 0);
}
return result || '';
}
} }

View File

@@ -26,7 +26,7 @@
</table> </table>
</div> </div>
<div class="dynamic-table-widget__buttons"> <div class="dynamic-table-widget__buttons" *ngIf="!readOnly">
<button class="mdl-button mdl-js-button mdl-button--icon" <button class="mdl-button mdl-js-button mdl-button--icon"
[disabled]="!hasSelection()" [disabled]="!hasSelection()"
(click)="moveSelectionUp()"> (click)="moveSelectionUp()">

View File

@@ -54,9 +54,9 @@ export class DynamicTableModel extends FormWidgetModel {
this.field = field; this.field = field;
if (field.json) { if (field.json) {
const columns = this.getColumns(field);
if (field.json.columnDefinitions) { if (columns) {
this.columns = field.json.columnDefinitions.map(obj => <DynamicTableColumn> obj); this.columns = columns;
this.visibleColumns = this.columns.filter(col => col.visible); this.visibleColumns = this.columns.filter(col => col.visible);
} }
@@ -72,6 +72,20 @@ export class DynamicTableModel extends FormWidgetModel {
]; ];
} }
private getColumns(field: FormFieldModel): DynamicTableColumn[] {
if (field && field.json) {
let definitions = field.json.columnDefinitions;
if (!definitions && field.json.params && field.json.params.field) {
definitions = field.json.params.field.columnDefinitions;
}
if (definitions) {
return definitions.map(obj => <DynamicTableColumn> obj);
}
}
return null;
}
flushValue() { flushValue() {
if (this.field) { if (this.field) {
this.field.value = this.rows.map(r => r.value); this.field.value = this.rows.map(r => r.value);

View File

@@ -15,11 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, ElementRef, OnInit } from '@angular/core'; import { Component, ElementRef, OnInit, Input } from '@angular/core';
import { LogService } from 'ng2-alfresco-core'; import { LogService } from 'ng2-alfresco-core';
import { WidgetComponent } from './../widget.component'; import { WidgetComponent } from './../widget.component';
import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './dynamic-table.widget.model'; import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './dynamic-table.widget.model';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service'; import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
import { FormFieldModel } from '../core/form-field.model';
@Component({ @Component({
moduleId: module.id, moduleId: module.id,
@@ -31,6 +32,12 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
ERROR_MODEL_NOT_FOUND = 'Table model not found'; ERROR_MODEL_NOT_FOUND = 'Table model not found';
@Input()
field: FormFieldModel;
@Input()
readOnly: boolean = false;
content: DynamicTableModel; content: DynamicTableModel;
editMode: boolean = false; editMode: boolean = false;
@@ -70,7 +77,7 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
} }
moveSelectionUp(): boolean { moveSelectionUp(): boolean {
if (this.content) { if (this.content && !this.readOnly) {
this.content.moveRow(this.content.selectedRow, -1); this.content.moveRow(this.content.selectedRow, -1);
return true; return true;
} }
@@ -78,7 +85,7 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
} }
moveSelectionDown(): boolean { moveSelectionDown(): boolean {
if (this.content) { if (this.content && !this.readOnly) {
this.content.moveRow(this.content.selectedRow, 1); this.content.moveRow(this.content.selectedRow, 1);
return true; return true;
} }
@@ -86,7 +93,7 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
} }
deleteSelection(): boolean { deleteSelection(): boolean {
if (this.content) { if (this.content && !this.readOnly) {
this.content.deleteRow(this.content.selectedRow); this.content.deleteRow(this.content.selectedRow);
return true; return true;
} }
@@ -94,7 +101,7 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
} }
addNewRow(): boolean { addNewRow(): boolean {
if (this.content) { if (this.content && !this.readOnly) {
this.editRow = <DynamicTableRow> { this.editRow = <DynamicTableRow> {
isNew: true, isNew: true,
selected: false, selected: false,
@@ -107,7 +114,7 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
} }
editSelection(): boolean { editSelection(): boolean {
if (this.content) { if (this.content && !this.readOnly) {
this.editRow = this.copyRow(this.content.selectedRow); this.editRow = this.copyRow(this.content.selectedRow);
this.editMode = true; this.editMode = true;
return true; return true;