mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-31 17:38:48 +00:00
[ADF-5390] [ADF-5391] Add multivalue cardview for Date, Datetime, Integers and Decimal properties. (#6980)
* [ADF-5390] Addd multivalue cardview for Date, Datetime, Integers and Decimal properties * Fix unit test * Fix linting * Fix e2e tests * fix e2e Co-authored-by: Eugenio Romano <eugenio.romano@alfresco.com>
This commit is contained in:
@@ -5,23 +5,23 @@
|
||||
</div>
|
||||
|
||||
<div class="adf-property-value adf-property-value-padding-top">
|
||||
<span *ngIf="!isEditable()"
|
||||
<span *ngIf="!isEditable() && !property.multivalued"
|
||||
[attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
|
||||
<span [attr.data-automation-id]="'card-dateitem-' + property.key">
|
||||
<span *ngIf="showProperty()"
|
||||
(dblclick)="copyToClipboard(property.displayValue)"
|
||||
matTooltipShowDelay="1000"
|
||||
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate">{{ property.displayValue }}</span>
|
||||
</span>
|
||||
<span *ngIf="showProperty()"
|
||||
[attr.data-automation-id]="'card-dateitem-' + property.key"
|
||||
(dblclick)="copyToClipboard(property.displayValue)"
|
||||
matTooltipShowDelay="1000"
|
||||
[matTooltip]="'CORE.METADATA.ACTIONS.COPY_TO_CLIPBOARD' | translate">{{ property.displayValue}}</span>
|
||||
</span>
|
||||
<div *ngIf="isEditable()"
|
||||
<div *ngIf="isEditable() && !property.multivalued"
|
||||
class="adf-dateitem-editable">
|
||||
<div class="adf-dateitem-editable-controls">
|
||||
<span class="adf-datepicker-toggle"
|
||||
[attr.data-automation-id]="'datepicker-label-toggle-' + property.key"
|
||||
(click)="showDatePicker()">
|
||||
<span *ngIf="showProperty(); else elseEmptyValueBlock"
|
||||
[attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">{{ property.displayValue }}</span>
|
||||
[attr.data-automation-id]="'card-' + property.type + '-value-' + property.key">
|
||||
{{ property.displayValue }}</span>
|
||||
</span>
|
||||
|
||||
<mat-icon *ngIf="showClearAction()"
|
||||
@@ -55,4 +55,42 @@
|
||||
<ng-template #elseEmptyValueBlock>
|
||||
{{ property.default | translate }}
|
||||
</ng-template>
|
||||
|
||||
<div *ngIf="property.multivalued"
|
||||
class="adf-property-field adf-dateitem-chip-list-container adf-dateitem-editable">
|
||||
<mat-chip-list #chipList
|
||||
class="adf-textitem-chip-list">
|
||||
<mat-chip *ngFor="let propertyValue of property.displayValue let idx = index"
|
||||
[removable]="isEditable"
|
||||
(removed)="removeValueFromList(idx)">
|
||||
{{ propertyValue }}
|
||||
<mat-icon *ngIf="isEditable()"
|
||||
matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<mat-form-field *ngIf="isEditable()"
|
||||
class="adf-property-field adf-dateitem-editable-controls"
|
||||
[floatLabel]="'never'"
|
||||
(click)="showDatePicker()">
|
||||
<input matInput
|
||||
class="adf-invisible-date-input"
|
||||
[attr.tabIndex]="-1"
|
||||
[matDatetimepicker]="datetimePicker"
|
||||
(dateChange)="addDateToList($event)">
|
||||
<mat-datetimepicker-toggle [attr.tabindex]="-1"
|
||||
matSuffix
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.data-automation-id]="'datepickertoggle-' + property.key"
|
||||
[for]="datetimePicker">
|
||||
</mat-datetimepicker-toggle>
|
||||
|
||||
<mat-datetimepicker #datetimePicker
|
||||
[type]="property.type"
|
||||
timeInterval="5"
|
||||
[attr.data-automation-id]="'datepicker-' + property.key"
|
||||
[startAt]="valueDate">
|
||||
</mat-datetimepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -13,6 +13,22 @@
|
||||
float: right;
|
||||
}
|
||||
|
||||
&-dateitem-chip-list-container.adf-property-field {
|
||||
margin-bottom: -7px !important;
|
||||
border-bottom: 0;
|
||||
cursor: pointer;
|
||||
|
||||
.adf-dateitem-editable-controls {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.mat-datetimepicker-toggle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -20px;
|
||||
}
|
||||
}
|
||||
|
||||
&-dateitem-editable {
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid mat-color($foreground, text, 0.42);
|
||||
@@ -53,6 +69,7 @@
|
||||
padding-left: 8px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&:hover mat-icon.adf-date-reset-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ import { CardViewDateItemComponent } from './card-view-dateitem.component';
|
||||
import { CoreTestingModule } from '../../../testing/core.testing.module';
|
||||
import { ClipboardService } from '../../../clipboard/clipboard.service';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
import { CardViewDatetimeItemModel } from './../../models/card-view-datetimeitem.model';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
describe('CardViewDateItemComponent', () => {
|
||||
@@ -192,7 +193,7 @@ describe('CardViewDateItemComponent', () => {
|
||||
component.editable = true;
|
||||
component.property.editable = true;
|
||||
const cardViewUpdateService = TestBed.inject(CardViewUpdateService);
|
||||
const expectedDate = moment('Jul 10 2017', 'MMM DD YY');
|
||||
const expectedDate = moment('Jul 10 2017', 'MMM DD YYYY');
|
||||
fixture.detectChanges();
|
||||
const property = { ...component.property };
|
||||
|
||||
@@ -231,7 +232,7 @@ describe('CardViewDateItemComponent', () => {
|
||||
component.editable = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const doubleClickEl = fixture.debugElement.query(By.css(`[data-automation-id="card-dateitem-${component.property.key}"] span`));
|
||||
const doubleClickEl = fixture.debugElement.query(By.css(`[data-automation-id="card-dateitem-${component.property.key}"]`));
|
||||
doubleClickEl.triggerEventHandler('dblclick', new MouseEvent('dblclick'));
|
||||
|
||||
fixture.detectChanges();
|
||||
@@ -346,4 +347,42 @@ describe('CardViewDateItemComponent', () => {
|
||||
fixture.detectChanges();
|
||||
expect(component.property.value).toEqual(expectedDate.toDate());
|
||||
});
|
||||
|
||||
it('should render chips for multivalue dates when chips are enabled', async () => {
|
||||
component.property = new CardViewDateItemModel({
|
||||
label: 'Text label',
|
||||
value: ['Jul 10 2017 00:01:00', 'Jul 11 2017 00:01:00', 'Jul 12 2017 00:01:00'],
|
||||
key: 'textkey',
|
||||
editable: true,
|
||||
multivalued: true
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const valueChips = fixture.debugElement.queryAll(By.css(`mat-chip`));
|
||||
expect(valueChips).not.toBeNull();
|
||||
expect(valueChips.length).toBe(3);
|
||||
expect(valueChips[0].nativeElement.innerText.trim()).toBe('Jul 10, 2017');
|
||||
expect(valueChips[1].nativeElement.innerText.trim()).toBe('Jul 11, 2017');
|
||||
expect(valueChips[2].nativeElement.innerText.trim()).toBe('Jul 12, 2017');
|
||||
});
|
||||
|
||||
it('should render chips for multivalue datetimes when chips are enabled', async () => {
|
||||
component.property = new CardViewDatetimeItemModel({
|
||||
label: 'Text label',
|
||||
value: ['Jul 10 2017 00:01:00', 'Jul 11 2017 00:01:00', 'Jul 12 2017 00:01:00'],
|
||||
key: 'textkey',
|
||||
editable: true,
|
||||
multivalued: true
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const valueChips = fixture.debugElement.queryAll(By.css(`mat-chip`));
|
||||
expect(valueChips).not.toBeNull();
|
||||
expect(valueChips.length).toBe(3);
|
||||
expect(valueChips[0].nativeElement.innerText.trim()).toBe('Jul 10, 2017, 0:01');
|
||||
expect(valueChips[1].nativeElement.innerText.trim()).toBe('Jul 11, 2017, 0:01');
|
||||
expect(valueChips[2].nativeElement.innerText.trim()).toBe('Jul 12, 2017, 0:01');
|
||||
});
|
||||
});
|
||||
|
@@ -89,6 +89,8 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
||||
|
||||
if (this.property.value) {
|
||||
this.valueDate = moment(this.property.value, this.dateFormat);
|
||||
} else if (this.property.multivalued && !this.property.value) {
|
||||
this.property.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,8 +120,8 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
||||
const momentDate = moment(newDateValue.value, this.dateFormat, true);
|
||||
if (momentDate.isValid()) {
|
||||
this.valueDate = momentDate;
|
||||
this.cardViewUpdateService.update(<CardViewDateItemModel> { ...this.property }, momentDate.toDate());
|
||||
this.property.value = momentDate.toDate();
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,4 +137,24 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
|
||||
const clipboardMessage = this.translateService.instant('CORE.METADATA.ACCESSIBILITY.COPY_TO_CLIPBOARD_MESSAGE');
|
||||
this.clipboardService.copyContentToClipboard(valueToCopy, clipboardMessage);
|
||||
}
|
||||
|
||||
addDateToList(newDateValue) {
|
||||
if (newDateValue) {
|
||||
const momentDate = moment(newDateValue.value, this.dateFormat, true);
|
||||
if (momentDate.isValid()) {
|
||||
this.property.value.push(momentDate.toDate());
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeValueFromList(itemIndex: number) {
|
||||
this.property.value.splice(itemIndex, 1);
|
||||
this.update();
|
||||
}
|
||||
|
||||
update() {
|
||||
this.cardViewUpdateService.update(<CardViewDateItemModel> { ...this.property }, this.property.value);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -72,7 +72,7 @@
|
||||
[floatLabel]="'never'">
|
||||
<input matInput
|
||||
class="adf-property-value"
|
||||
[placeholder]="property.default | translate"
|
||||
[placeholder]="editedValue ? '' : property.default | translate"
|
||||
[matChipInputFor]="chipList"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addValueToList($event)"
|
||||
|
@@ -180,7 +180,48 @@ describe('CardViewTextItemComponent', () => {
|
||||
expect(valueChips[0].nativeElement.innerText.trim()).toBe('item1');
|
||||
expect(valueChips[1].nativeElement.innerText.trim()).toBe('item2');
|
||||
expect(valueChips[2].nativeElement.innerText.trim()).toBe('item3');
|
||||
});
|
||||
|
||||
it('should render chips for multivalue integers when chips are enabled', async () => {
|
||||
component.property = new CardViewIntItemModel({
|
||||
label: 'Text label',
|
||||
value: [1, 2, 3],
|
||||
key: 'textkey',
|
||||
editable: true,
|
||||
multivalued: true
|
||||
});
|
||||
component.useChipsForMultiValueProperty = true;
|
||||
component.ngOnChanges({ property: new SimpleChange(null, null, true) });
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const valueChips = fixture.debugElement.queryAll(By.css(`mat-chip`));
|
||||
expect(valueChips).not.toBeNull();
|
||||
expect(valueChips.length).toBe(3);
|
||||
expect(valueChips[0].nativeElement.innerText.trim()).toBe('1');
|
||||
expect(valueChips[1].nativeElement.innerText.trim()).toBe('2');
|
||||
expect(valueChips[2].nativeElement.innerText.trim()).toBe('3');
|
||||
});
|
||||
|
||||
it('should render chips for multivalue decimal numbers when chips are enabled', async () => {
|
||||
component.property = new CardViewFloatItemModel({
|
||||
label: 'Text label',
|
||||
value: [1.1, 2.2, 3.3],
|
||||
key: 'textkey',
|
||||
editable: true,
|
||||
multivalued: true
|
||||
});
|
||||
component.useChipsForMultiValueProperty = true;
|
||||
component.ngOnChanges({ property: new SimpleChange(null, null, true) });
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const valueChips = fixture.debugElement.queryAll(By.css(`mat-chip`));
|
||||
expect(valueChips).not.toBeNull();
|
||||
expect(valueChips.length).toBe(3);
|
||||
expect(valueChips[0].nativeElement.innerText.trim()).toBe('1.1');
|
||||
expect(valueChips[1].nativeElement.innerText.trim()).toBe('2.2');
|
||||
expect(valueChips[2].nativeElement.innerText.trim()).toBe('3.3');
|
||||
});
|
||||
|
||||
it('should render string for multivalue properties when chips are disabled', async () => {
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { CardViewTextItemModel } from '../../models/card-view-textitem.model';
|
||||
import { CardViewUpdateService } from '../../services/card-view-update.service';
|
||||
import { BaseCardView } from '../base-card-view';
|
||||
@@ -68,7 +68,8 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
||||
|
||||
constructor(cardViewUpdateService: CardViewUpdateService,
|
||||
private clipboardService: ClipboardService,
|
||||
private translateService: TranslationService) {
|
||||
private translateService: TranslationService,
|
||||
private cd: ChangeDetectorRef) {
|
||||
super(cardViewUpdateService);
|
||||
}
|
||||
|
||||
@@ -76,7 +77,7 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
||||
if (changes.property && changes.property.firstChange) {
|
||||
this.textInput.valueChanges
|
||||
.pipe(
|
||||
filter(textInputValue => textInputValue !== this.editedValue),
|
||||
filter(textInputValue => textInputValue !== this.editedValue && textInputValue !== null),
|
||||
debounceTime(50),
|
||||
takeUntil(this.onDestroy$)
|
||||
)
|
||||
@@ -125,9 +126,8 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
||||
|
||||
update(): void {
|
||||
if (this.property.isValid(this.editedValue)) {
|
||||
const updatedValue = this.prepareValueForUpload(this.property, this.editedValue);
|
||||
this.cardViewUpdateService.update(<CardViewTextItemModel> { ...this.property }, updatedValue);
|
||||
this.property.value = updatedValue;
|
||||
this.property.value = this.prepareValueForUpload(this.property, this.editedValue);
|
||||
this.cardViewUpdateService.update(<CardViewTextItemModel> { ...this.property }, this.property.value);
|
||||
this.resetErrorMessages();
|
||||
} else {
|
||||
this.errors = this.property.getValidationErrors(this.editedValue);
|
||||
@@ -143,9 +143,10 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
|
||||
}
|
||||
|
||||
removeValueFromList(itemIndex: number) {
|
||||
if (typeof this.editedValue !== 'string') {
|
||||
if (Array.isArray(this.editedValue)) {
|
||||
this.editedValue.splice(itemIndex, 1);
|
||||
this.update();
|
||||
this.cd.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user