From cb23103c830c9f6e36c46d0387f41d70a9b0b29d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Bolbo=C8=99enco?= Date: Mon, 25 Jun 2018 19:04:46 +0300 Subject: [PATCH] [ADF-3193] CardView Variables Item (#3485) * variables item * unit tests * translations fix * docs added * change requests * change requests --- docs/core/card-view.component.md | 23 +++ lib/core/card-view/card-view.module.ts | 10 +- ...card-view-keyvaluepairsitem.component.html | 58 ++++++ ...card-view-keyvaluepairsitem.component.scss | 22 +++ ...d-view-keyvaluepairsitem.component.spec.ts | 176 ++++++++++++++++++ .../card-view-keyvaluepairsitem.component.ts | 75 ++++++++ .../components/card-view.components.ts | 1 + ...-keyvaluepairsitem-properties.interface.ts | 27 +++ .../interfaces/card-view.interfaces.ts | 1 + .../models/card-view-keyvaluepairs.model.ts | 33 ++++ lib/core/card-view/models/card-view.models.ts | 1 + lib/core/card-view/public-api.ts | 3 +- .../services/card-item-types.service.ts | 4 +- lib/core/i18n/en.json | 5 + 14 files changed, 435 insertions(+), 4 deletions(-) create mode 100644 lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.html create mode 100644 lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.scss create mode 100644 lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.spec.ts create mode 100644 lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.ts create mode 100644 lib/core/card-view/interfaces/card-view-keyvaluepairsitem-properties.interface.ts create mode 100644 lib/core/card-view/models/card-view-keyvaluepairs.model.ts diff --git a/docs/core/card-view.component.md b/docs/core/card-view.component.md index b31eeeec57..0172055ed0 100644 --- a/docs/core/card-view.component.md +++ b/docs/core/card-view.component.md @@ -74,6 +74,11 @@ Defining properties from Typescript: key: 'mental-stability', default: 0.0 }), + new CardViewKeyValuePairsItemModel({ + label: 'Variables', + value: [], + key: 'key-value-pairs' + }), ... ] ``` @@ -99,6 +104,7 @@ You define the property list, the [`CardViewComponent`](../core/card-view.compon - [**CardViewBoolItemModel**](#card-bool-item) - _for bool items (checkbox)_ - [**CardViewIntItemModel**](#card-int-item) - _for integer items_ - [**CardViewFloatItemModel**](#card-float-item) - _for float items_ +- [**CardViewKeyValuePairsItemModel**](#card-key-values-pairs-item) - _for key-value-pairs items_ Each of these types implements the [Card View Item interface](card-view-item.interface.md): @@ -287,6 +293,23 @@ const floatItemProperty = new CardViewFloatItemModel(options); | displayValue\* | float | | The value to display | | editable | boolean | false | Toggles whether the item is editable | +#### Card Key Value Pairs Item + +[`CardViewKeyValuePairsItemModel`](../../lib/core/card-view/models/card-view-keyvaluepairs.model.ts) is a property type for key-value properties. + +```ts +const keyValuePairsItemProperty = new CardViewKeyValuePairsItemModel(options); +``` + +| Name | Type | Default | Description | +| ---- | ---- | ------- | ----------- | +| label\* | string | | Item label | +| key\* | string | | Identifying key (important when editing the item) | +| editable | boolean | false | Toggles whether the item is editable | +| value\* | `[{ name: '', value: '' }, ...]` | | The original data value for the item | + + + ## See also - [Card View Update service](card-view-update.service.md) diff --git a/lib/core/card-view/card-view.module.ts b/lib/core/card-view/card-view.module.ts index ae5f2e068f..303932e299 100644 --- a/lib/core/card-view/card-view.module.ts +++ b/lib/core/card-view/card-view.module.ts @@ -21,6 +21,7 @@ import { FormsModule } from '@angular/forms'; import { MatButtonModule, MatDatepickerModule, + MatTableModule, MatIconModule, MatInputModule, MatCheckboxModule, @@ -37,6 +38,7 @@ import { CardViewDateItemComponent } from './components/card-view-dateitem/card- import { CardViewItemDispatcherComponent } from './components/card-view-item-dispatcher/card-view-item-dispatcher.component'; import { CardViewMapItemComponent } from './components/card-view-mapitem/card-view-mapitem.component'; import { CardViewTextItemComponent } from './components/card-view-textitem/card-view-textitem.component'; +import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component'; @NgModule({ imports: [ @@ -48,6 +50,7 @@ import { CardViewTextItemComponent } from './components/card-view-textitem/card- MatNativeDateModule, MatCheckboxModule, MatInputModule, + MatTableModule, MatIconModule, MatButtonModule, MatDatetimepickerModule, @@ -59,6 +62,7 @@ import { CardViewTextItemComponent } from './components/card-view-textitem/card- CardViewDateItemComponent, CardViewMapItemComponent, CardViewTextItemComponent, + CardViewKeyValuePairsItemComponent, CardViewItemDispatcherComponent, CardViewContentProxyDirective ], @@ -66,14 +70,16 @@ import { CardViewTextItemComponent } from './components/card-view-textitem/card- CardViewBoolItemComponent, CardViewDateItemComponent, CardViewMapItemComponent, - CardViewTextItemComponent + CardViewTextItemComponent, + CardViewKeyValuePairsItemComponent ], exports: [ CardViewComponent, CardViewBoolItemComponent, CardViewDateItemComponent, CardViewMapItemComponent, - CardViewTextItemComponent + CardViewTextItemComponent, + CardViewKeyValuePairsItemComponent ] }) export class CardViewModule {} diff --git a/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.html b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.html new file mode 100644 index 0000000000..c4e71ce7a9 --- /dev/null +++ b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.html @@ -0,0 +1,58 @@ +
{{ property.label | translate }}
+
+ +
+ {{ 'CORE.CARDVIEW.KEYVALUEPAIRS.ADD' | translate }} + +
+ +
+ + + {{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }} + {{item.name}} + + + {{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }} + {{item.value}} + + + + + +
+ + +
+
+
{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.NAME' | translate }}
+
{{ 'CORE.CARDVIEW.KEYVALUEPAIRS.VALUE' | translate }}
+
+ +
+
+ + + +
+
+ + + +
+ +
+
+
diff --git a/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.scss b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.scss new file mode 100644 index 0000000000..84caf9ce97 --- /dev/null +++ b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.scss @@ -0,0 +1,22 @@ +.card-view { + &__key-value-pairs { + &__col { + display: inline-block; + width: 39%; + + .mat-form-field { + width: 100%; + } + } + + &__read-only { + .mat-table { + box-shadow: none; + } + + .mat-header-row, .mat-row { + padding: 0; + } + } + } +} diff --git a/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.spec.ts b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.spec.ts new file mode 100644 index 0000000000..c81e8cccd2 --- /dev/null +++ b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.spec.ts @@ -0,0 +1,176 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { CardViewKeyValuePairsItemModel } from '../../models/card-view-keyvaluepairs.model'; +import { CardViewKeyValuePairsItemComponent } from './card-view-keyvaluepairsitem.component'; +import { setupTestBed } from '../../../testing/setupTestBed'; +import { CoreTestingModule } from '../../../testing/core.testing.module'; +import { CardViewUpdateService } from '../../services/card-view-update.service'; + +describe('CardViewKeyValuePairsItemComponent', () => { + + let fixture: ComponentFixture; + let component: CardViewKeyValuePairsItemComponent; + let cardViewUpdateService; + const mockEmptyData = [{ name: '', value: '' }]; + const mockData = [{ name: 'test-name', value: 'test-value' }]; + + setupTestBed({ + imports: [CoreTestingModule] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CardViewKeyValuePairsItemComponent); + cardViewUpdateService = TestBed.get(CardViewUpdateService); + component = fixture.componentInstance; + component.property = new CardViewKeyValuePairsItemModel({ + label: 'Key Value Pairs', + value: [], + key: 'key-value-pairs', + editable: true + }); + component.editable = true; + }); + + afterEach(() => { + fixture.destroy(); + }); + + describe('Component', () => { + + it('should render the label', () => { + fixture.detectChanges(); + + const labelValue = fixture.debugElement.query(By.css('.adf-property-label')); + expect(labelValue).not.toBeNull(); + expect(labelValue.nativeElement.innerText).toBe('Key Value Pairs'); + }); + + it('should render readOnly table is editable property is FALSE', () => { + component.property = new CardViewKeyValuePairsItemModel({ + label: 'Key Value Pairs', + value: mockData, + key: 'key-value-pairs' + }); + + component.ngOnChanges(); + fixture.detectChanges(); + + const table = fixture.debugElement.query(By.css('.card-view__key-value-pairs__read-only')); + const form = fixture.debugElement.query(By.css('.card-view__key-value-pairs')); + + expect(table).not.toBeNull(); + expect(form).toBeNull(); + }); + + it('should add new item on ADD button click', () => { + component.ngOnChanges(); + fixture.detectChanges(); + + const addButton = fixture.debugElement.query(By.css('.card-view__key-value-pairs__add-btn')); + addButton.triggerEventHandler('click', null); + fixture.detectChanges(); + + expect(JSON.stringify(component.values)).toBe(JSON.stringify(mockEmptyData)); + + const content = fixture.debugElement.query(By.css('.card-view__key-value-pairs')); + expect(content).not.toBeNull(); + + let nameInput = fixture.debugElement.query(By.css(`[data-automation-id="card-${component.property.key}-name-input-0"]`)); + let valueInput = fixture.debugElement.query(By.css(`[data-automation-id="card-${component.property.key}-value-input-0"]`)); + expect(nameInput).not.toBeNull(); + expect(valueInput).not.toBeNull(); + + }); + + it('should remove an item from list on REMOVE button click', () => { + spyOn(cardViewUpdateService, 'update'); + component.ngOnChanges(); + fixture.detectChanges(); + + const addButton = fixture.debugElement.query(By.css('.card-view__key-value-pairs__add-btn')); + addButton.triggerEventHandler('click', null); + fixture.detectChanges(); + + const removeButton = fixture.debugElement.query(By.css('.card-view__key-value-pairs__remove-btn')); + removeButton.triggerEventHandler('click', null); + fixture.detectChanges(); + + expect(component.values.length).toBe(0); + const content = fixture.debugElement.query(By.css('.card-view__key-value-pairs')); + expect(content).toBeNull(); + + expect(cardViewUpdateService.update).toHaveBeenCalled(); + expect(component.property.value.length).toBe(0); + }); + + it('should update property on input blur', async(() => { + spyOn(cardViewUpdateService, 'update'); + component.ngOnChanges(); + fixture.detectChanges(); + + const addButton = fixture.debugElement.query(By.css('.card-view__key-value-pairs__add-btn')); + addButton.triggerEventHandler('click', null); + fixture.detectChanges(); + + let nameInput = fixture.debugElement.query(By.css(`[data-automation-id="card-${component.property.key}-name-input-0"]`)); + let valueInput = fixture.debugElement.query(By.css(`[data-automation-id="card-${component.property.key}-value-input-0"]`)); + + nameInput.nativeElement.value = mockData[0].name; + nameInput.nativeElement.dispatchEvent(new Event('input')); + valueInput.nativeElement.value = mockData[0].value; + valueInput.nativeElement.dispatchEvent(new Event('input')); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + + valueInput.triggerEventHandler('blur', null); + fixture.detectChanges(); + + expect(cardViewUpdateService.update).toHaveBeenCalled(); + expect(JSON.stringify(component.property.value)).toBe(JSON.stringify(mockData)); + }); + })); + + it('should not update property if at least one input is empty on blur', async(() => { + spyOn(cardViewUpdateService, 'update'); + component.ngOnChanges(); + fixture.detectChanges(); + + const addButton = fixture.debugElement.query(By.css('.card-view__key-value-pairs__add-btn')); + addButton.triggerEventHandler('click', null); + fixture.detectChanges(); + + let valueInput = fixture.debugElement.query(By.css(`[data-automation-id="card-${component.property.key}-value-input-0"]`)); + + valueInput.nativeElement.value = mockData[0].value; + valueInput.nativeElement.dispatchEvent(new Event('input')); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + + valueInput.triggerEventHandler('blur', null); + fixture.detectChanges(); + + expect(cardViewUpdateService.update).not.toHaveBeenCalled(); + }); + })); + + }); +}); diff --git a/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.ts b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.ts new file mode 100644 index 0000000000..cab8beacb9 --- /dev/null +++ b/lib/core/card-view/components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component.ts @@ -0,0 +1,75 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, Input, OnChanges } from '@angular/core'; +import { CardViewUpdateService } from '../../services/card-view-update.service'; +import { CardViewKeyValuePairsItemModel } from '../../models/card-view.models'; +import { CardViewKeyValuePairsItemType } from '../../interfaces/card-view.interfaces'; +import { MatTableDataSource } from '@angular/material'; + +@Component({ + selector: 'adf-card-view-boolitem', + templateUrl: './card-view-keyvaluepairsitem.component.html', + styleUrls: ['./card-view-keyvaluepairsitem.component.scss'] +}) + +export class CardViewKeyValuePairsItemComponent implements OnChanges { + + @Input() + property: CardViewKeyValuePairsItemModel; + + @Input() + editable: boolean = false; + + values: CardViewKeyValuePairsItemType[]; + matTableValues: MatTableDataSource; + + constructor(private cardViewUpdateService: CardViewUpdateService) {} + + ngOnChanges() { + this.values = this.property.value || []; + this.matTableValues = new MatTableDataSource(this.values); + } + + isEditable(): boolean { + return this.editable && this.property.editable; + } + + add(): void { + this.values.push({ name: '', value: '' }); + } + + remove(index: number): void { + this.values.splice(index, 1); + this.save(true); + } + + onBlur(value): void { + if (value.length) { + this.save(); + } + } + + save(remove?: boolean): void { + const validValues = this.values.filter(i => i.name.length && i.value.length); + + if (remove || validValues.length) { + this.cardViewUpdateService.update(this.property, validValues); + this.property.value = validValues; + } + } +} diff --git a/lib/core/card-view/components/card-view.components.ts b/lib/core/card-view/components/card-view.components.ts index 3187f44ff6..be4ab5d798 100644 --- a/lib/core/card-view/components/card-view.components.ts +++ b/lib/core/card-view/components/card-view.components.ts @@ -21,3 +21,4 @@ export * from './card-view-dateitem/card-view-dateitem.component'; export * from './card-view-item-dispatcher/card-view-item-dispatcher.component'; export * from './card-view-mapitem/card-view-mapitem.component'; export * from './card-view-textitem/card-view-textitem.component'; +export * from './card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component'; diff --git a/lib/core/card-view/interfaces/card-view-keyvaluepairsitem-properties.interface.ts b/lib/core/card-view/interfaces/card-view-keyvaluepairsitem-properties.interface.ts new file mode 100644 index 0000000000..3cd011e045 --- /dev/null +++ b/lib/core/card-view/interfaces/card-view-keyvaluepairsitem-properties.interface.ts @@ -0,0 +1,27 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CardViewItemProperties } from './card-view-item-properties.interface'; + +export interface CardViewKeyValuePairsItemType { + name: string; + value: string; +} + +export interface CardViewKeyValuePairsItemProperties extends CardViewItemProperties { + value: CardViewKeyValuePairsItemType[]; +} diff --git a/lib/core/card-view/interfaces/card-view.interfaces.ts b/lib/core/card-view/interfaces/card-view.interfaces.ts index a28204cf4c..137ae05b8b 100644 --- a/lib/core/card-view/interfaces/card-view.interfaces.ts +++ b/lib/core/card-view/interfaces/card-view.interfaces.ts @@ -22,3 +22,4 @@ export * from './card-view-textitem-properties.interface'; export * from './card-view-dateitem-properties.interface'; export * from './card-view-boolitem-properties.interface'; export * from './card-view-textitem-pipe-property.interface'; +export * from './card-view-keyvaluepairsitem-properties.interface'; diff --git a/lib/core/card-view/models/card-view-keyvaluepairs.model.ts b/lib/core/card-view/models/card-view-keyvaluepairs.model.ts new file mode 100644 index 0000000000..1c986f2021 --- /dev/null +++ b/lib/core/card-view/models/card-view-keyvaluepairs.model.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CardViewItem } from '../interfaces/card-view-item.interface'; +import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service'; +import { CardViewBaseItemModel } from './card-view-baseitem.model'; +import { CardViewKeyValuePairsItemProperties } from '../interfaces/card-view.interfaces'; + +export class CardViewKeyValuePairsItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel { + type: string = 'keyvaluepairs'; + + constructor(obj: CardViewKeyValuePairsItemProperties) { + super(obj); + } + + get displayValue() { + return this.value; + } +} diff --git a/lib/core/card-view/models/card-view.models.ts b/lib/core/card-view/models/card-view.models.ts index 0d16dc6552..e29adc1f4c 100644 --- a/lib/core/card-view/models/card-view.models.ts +++ b/lib/core/card-view/models/card-view.models.ts @@ -23,3 +23,4 @@ export * from './card-view-floatitem.model'; export * from './card-view-intitem.model'; export * from './card-view-mapitem.model'; export * from './card-view-textitem.model'; +export * from './card-view-keyvaluepairs.model'; diff --git a/lib/core/card-view/public-api.ts b/lib/core/card-view/public-api.ts index 68ec4b151c..0ae9787d11 100644 --- a/lib/core/card-view/public-api.ts +++ b/lib/core/card-view/public-api.ts @@ -20,7 +20,8 @@ export { CardViewBoolItemComponent, CardViewDateItemComponent, CardViewMapItemComponent, - CardViewTextItemComponent + CardViewTextItemComponent, + CardViewKeyValuePairsItemComponent } from './components/card-view.components'; export * from './interfaces/card-view.interfaces'; diff --git a/lib/core/card-view/services/card-item-types.service.ts b/lib/core/card-view/services/card-item-types.service.ts index e237d44005..ba12c44678 100644 --- a/lib/core/card-view/services/card-item-types.service.ts +++ b/lib/core/card-view/services/card-item-types.service.ts @@ -20,6 +20,7 @@ import { CardViewDateItemComponent } from '../components/card-view-dateitem/card import { CardViewMapItemComponent } from '../components/card-view-mapitem/card-view-mapitem.component'; import { CardViewTextItemComponent } from '../components/card-view-textitem/card-view-textitem.component'; import { CardViewBoolItemComponent } from '../components/card-view-boolitem/card-view-boolitem.component'; +import { CardViewKeyValuePairsItemComponent } from '../components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component'; import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../services/dynamic-component-mapper.service'; @Injectable() @@ -34,6 +35,7 @@ export class CardItemTypeService extends DynamicComponentMapper { 'date': DynamicComponentResolver.fromType(CardViewDateItemComponent), 'datetime': DynamicComponentResolver.fromType(CardViewDateItemComponent), 'bool': DynamicComponentResolver.fromType(CardViewBoolItemComponent), - 'map': DynamicComponentResolver.fromType(CardViewMapItemComponent) + 'map': DynamicComponentResolver.fromType(CardViewMapItemComponent), + 'keyvaluepairs': DynamicComponentResolver.fromType(CardViewKeyValuePairsItemComponent) }; } diff --git a/lib/core/i18n/en.json b/lib/core/i18n/en.json index 4fc92119f6..8a1303806c 100644 --- a/lib/core/i18n/en.json +++ b/lib/core/i18n/en.json @@ -138,6 +138,11 @@ "CLIENT": "ClientId" }, "CARDVIEW": { + "KEYVALUEPAIRS": { + "ADD": "Add new", + "NAME": "Name", + "VALUE": "Value" + }, "VALIDATORS": { "FLOAT_VALIDATION_ERROR": "Use a number format", "INT_VALIDATION_ERROR": "Use an integer format"