[ADF-3484] - Metadata drop-down list option for properties constrained by a list of values (#5892)

* update js-api

* include definition field

* process LIST constraint

* update tests

* dropdown visibility

* optional chaining
This commit is contained in:
Cilibiu Bogdan
2020-07-22 00:46:46 +03:00
committed by GitHub
parent 826bd32e60
commit 5257917258
10 changed files with 4337 additions and 3332 deletions

View File

@@ -66,7 +66,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
showVersions = false;
allowDropFiles = true;
displayMode = DisplayMode.List;
includeFields = ['isFavorite', 'isLocked', 'aspectNames'];
includeFields = ['isFavorite', 'isLocked', 'aspectNames', 'definition'];
baseShareUrl = (
this.appConfig.get<string>(AppConfigValues.BASESHAREURL) ||

View File

@@ -63,7 +63,7 @@ export class ContentMetadataService {
map((groups) => contentMetadataConfig.filterExcludedPreset(groups)),
map((groups) => this.filterEmptyPreset(groups)),
map((groups) => this.setTitleToNameIfNotSet(groups)),
map((groups) => this.propertyGroupTranslatorService.translateToCardViewGroups(groups, node.properties))
map((groups) => this.propertyGroupTranslatorService.translateToCardViewGroups(groups, node.properties, node.definition))
);
}
}

View File

@@ -26,10 +26,13 @@ import {
LogService,
CardViewBoolItemModel,
CardViewDatetimeItemModel,
setupTestBed
CardViewSelectItemModel,
setupTestBed,
CardViewSelectItemProperties
} from '@alfresco/adf-core';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { Constraint, Definition } from '@alfresco/js-api';
describe('PropertyGroupTranslatorService', () => {
@@ -95,7 +98,7 @@ describe('PropertyGroupTranslatorService', () => {
propertyValues = { 'FAS:PLAGUE': 'The Chariot Line' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
expect(cardViewGroup[0].properties.length).toBe(2);
expect(cardViewGroup[0].properties[0] instanceof CardViewTextItemModel).toBeTruthy('First property should be instance of CardViewTextItemModel');
expect(cardViewGroup[0].properties[1] instanceof CardViewTextItemModel).toBeTruthy('Second property should be instance of CardViewTextItemModel');
@@ -127,7 +130,7 @@ describe('PropertyGroupTranslatorService', () => {
propertyValues = { 'FAS:PLAGUE': 'The Chariot Line' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
expect(cardViewGroup.length).toBe(2);
expect(cardViewGroup[0].properties[0] instanceof CardViewTextItemModel).toBeTruthy('First group\'s property should be instance of CardViewTextItemModel');
expect(cardViewGroup[1].properties[0] instanceof CardViewTextItemModel).toBeTruthy('Second group\'s property should be instance of CardViewTextItemModel');
@@ -145,7 +148,7 @@ describe('PropertyGroupTranslatorService', () => {
propertyGroups.push(Object.assign({}, propertyGroup));
service.translateToCardViewGroups(propertyGroups, propertyValues);
service.translateToCardViewGroups(propertyGroups, propertyValues, null);
expect(logService.error).toHaveBeenCalledWith('Unknown type for mapping: daemonic:scorcher');
});
@@ -161,7 +164,7 @@ describe('PropertyGroupTranslatorService', () => {
propertyValues = { 'FAS:PLAGUE': 'The Chariot Line' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewTextItemModel = <CardViewTextItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewTextItemModel).toBeTruthy('Property should be instance of CardViewTextItemModel');
});
@@ -181,7 +184,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = dataType;
propertyValues = { 'prefix:name': null };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty = cardViewGroup[0].properties[0];
expect(cardViewProperty.label).toBe(property.title);
@@ -195,7 +198,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:text';
propertyValues = { 'FAS:PLAGUE': 'The Chariot Line' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewTextItemModel = <CardViewTextItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewTextItemModel).toBeTruthy('Property should be instance of CardViewTextItemModel');
@@ -207,7 +210,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:mltext';
propertyValues = { 'FAS:PLAGUE': 'The Chariot Line' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewTextItemModel = <CardViewTextItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewTextItemModel).toBeTruthy('Property should be instance of CardViewTextItemModel');
@@ -220,7 +223,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:date';
propertyValues = { 'FAS:PLAGUE': expectedValue };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewDateItemModel = <CardViewDateItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewDateItemModel).toBeTruthy('Property should be instance of CardViewDateItemModel');
@@ -232,7 +235,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:datetime';
propertyValues = { 'FAS:PLAGUE': expectedValue };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewDatetimeItemModel = <CardViewDatetimeItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewDatetimeItemModel).toBeTruthy('Property should be instance of CardViewDatetimeItemModel');
@@ -243,7 +246,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:int';
propertyValues = { 'FAS:PLAGUE': '1024' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewIntItemModel = <CardViewIntItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewIntItemModel).toBeTruthy('Property should be instance of CardViewIntItemModel');
@@ -254,7 +257,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:long';
propertyValues = { 'FAS:PLAGUE': '1024' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewIntItemModel = <CardViewIntItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewIntItemModel).toBeTruthy('Property should be instance of CardViewIntItemModel');
@@ -265,7 +268,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:float';
propertyValues = { 'FAS:PLAGUE': '1024.24' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewFloatItemModel = <CardViewFloatItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewFloatItemModel).toBeTruthy('Property should be instance of CardViewFloatItemModel');
@@ -276,7 +279,7 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:double';
propertyValues = { 'FAS:PLAGUE': '1024.24' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewFloatItemModel = <CardViewFloatItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewFloatItemModel).toBeTruthy('Property should be instance of CardViewFloatItemModel');
@@ -287,11 +290,34 @@ describe('PropertyGroupTranslatorService', () => {
property.dataType = 'd:boolean';
propertyValues = { 'FAS:PLAGUE': true };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues);
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, null);
const cardViewProperty: CardViewBoolItemModel = <CardViewBoolItemModel> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewBoolItemModel).toBeTruthy('Property should be instance of CardViewBoolItemModel');
expect(cardViewProperty.value).toBe(true);
});
it('should translate property for type LIST constraint', () => {
const definition: Definition = {
properties: [{
id: 'FAS:PLAGUE',
constraints: [
{
type: 'LIST',
parameters: {
allowedValues: ['one', 'two', 'three']
}
}
]
} as Constraint ]
};
property.dataType = 'd:text';
propertyValues = { 'FAS:PLAGUE': 'two' };
const cardViewGroup = service.translateToCardViewGroups(propertyGroups, propertyValues, definition);
const cardViewProperty: CardViewSelectItemModel<CardViewSelectItemProperties<string>> = <CardViewSelectItemModel<CardViewSelectItemProperties<string>>> cardViewGroup[0].properties[0];
expect(cardViewProperty instanceof CardViewSelectItemModel).toBeTruthy('Property should be instance of CardViewBoolItemModel');
expect(cardViewProperty.value).toBe('two');
});
});
});

View File

@@ -22,6 +22,7 @@ import {
CardViewTextItemModel,
CardViewBoolItemModel,
CardViewDateItemModel,
CardViewSelectItemModel,
CardViewDatetimeItemModel,
CardViewIntItemModel,
CardViewFloatItemModel,
@@ -31,6 +32,8 @@ import {
DecimalNumberPipe
} from '@alfresco/adf-core';
import { Property, CardViewGroup, OrganisedPropertyGroup } from '../interfaces/content-metadata.interfaces';
import { of } from 'rxjs';
import { Definition, Constraint } from '@alfresco/js-api';
const D_TEXT = 'd:text';
const D_MLTEXT = 'd:mltext';
@@ -58,21 +61,21 @@ export class PropertyGroupTranslatorService {
this.valueSeparator = this.appConfig.get<string>('content-metadata.multi-value-pipe-separator');
}
public translateToCardViewGroups(propertyGroups: OrganisedPropertyGroup[], propertyValues): CardViewGroup[] {
public translateToCardViewGroups(propertyGroups: OrganisedPropertyGroup[], propertyValues, definition: Definition): CardViewGroup[] {
return propertyGroups.map((propertyGroup) => {
const translatedPropertyGroup: any = Object.assign({}, propertyGroup);
translatedPropertyGroup.properties = this.translateArray(propertyGroup.properties, propertyValues);
translatedPropertyGroup.properties = this.translateArray(propertyGroup.properties, propertyValues, definition);
return translatedPropertyGroup;
});
}
private translateArray(properties: Property[], propertyValues: any): CardViewItem[] {
private translateArray(properties: Property[], propertyValues: any, definition: Definition): CardViewItem[] {
return properties.map((property) => {
return this.translate(property, propertyValues);
return this.translate(property, propertyValues, this.getPropertyConstraints(property.name, definition));
});
}
private translate(property: Property, propertyValues: any): CardViewItem {
private translate(property: Property, propertyValues: any, constraints: Constraint[]): CardViewItem {
let propertyValue;
if (propertyValues && propertyValues[property.name]) {
propertyValue = propertyValues[property.name];
@@ -87,54 +90,70 @@ export class PropertyGroupTranslatorService {
value: propertyValue,
key: `${prefix}${property.name}`,
default: property.defaultValue,
editable: property.editable !== undefined ? property.editable : true
editable: property.editable !== undefined ? property.editable : true,
constraints: constraints
};
let cardViewItemProperty;
switch (property.dataType) {
if (this.isListOfValues(propertyDefinition.constraints)) {
const options = propertyDefinition.constraints[0].parameters.allowedValues.map((value) => ({ key: value, label: value }));
const properties = Object.assign(propertyDefinition, { options$: of(options) });
case D_MLTEXT:
cardViewItemProperty = new CardViewTextItemModel(Object.assign(propertyDefinition, {
multiline: true
}));
break;
cardViewItemProperty = new CardViewSelectItemModel(properties);
} else {
switch (property.dataType) {
case D_MLTEXT:
cardViewItemProperty = new CardViewTextItemModel(Object.assign(propertyDefinition, {
multiline: true
}));
break;
case D_INT:
case D_LONG:
cardViewItemProperty = new CardViewIntItemModel(propertyDefinition);
break;
case D_INT:
case D_LONG:
cardViewItemProperty = new CardViewIntItemModel(propertyDefinition);
break;
case D_FLOAT:
case D_DOUBLE:
cardViewItemProperty = new CardViewFloatItemModel(Object.assign(propertyDefinition, {
pipes: [{ pipe: this.decimalNumberPipe }]
}));
break;
case D_FLOAT:
case D_DOUBLE:
cardViewItemProperty = new CardViewFloatItemModel(Object.assign(propertyDefinition, {
pipes: [{ pipe: this.decimalNumberPipe }]
}));
break;
case D_DATE:
cardViewItemProperty = new CardViewDateItemModel(propertyDefinition);
break;
case D_DATE:
cardViewItemProperty = new CardViewDateItemModel(propertyDefinition);
break;
case D_DATETIME:
cardViewItemProperty = new CardViewDatetimeItemModel(propertyDefinition);
break;
case D_DATETIME:
cardViewItemProperty = new CardViewDatetimeItemModel(propertyDefinition);
break;
case D_BOOLEAN:
cardViewItemProperty = new CardViewBoolItemModel(propertyDefinition);
break;
case D_BOOLEAN:
cardViewItemProperty = new CardViewBoolItemModel(propertyDefinition);
break;
case D_TEXT:
default:
cardViewItemProperty = new CardViewTextItemModel(Object.assign(propertyDefinition, {
multivalued: property.multiValued,
multiline: property.multiValued,
pipes: [{ pipe: this.multiValuePipe, params: [this.valueSeparator]}]
}));
case D_TEXT:
default:
cardViewItemProperty = new CardViewTextItemModel(Object.assign(propertyDefinition, {
multivalued: property.multiValued,
multiline: property.multiValued,
pipes: [{ pipe: this.multiValuePipe, params: [this.valueSeparator]}]
}));
}
}
return cardViewItemProperty;
}
private isListOfValues(constraint: Constraint[]): boolean {
return constraint?.[0]?.type === 'LIST';
}
private getPropertyConstraints(propertyName: string, definition: Definition): Constraint[] {
return definition?.properties.find((item) => item.id === propertyName)?.constraints ?? [];
}
private checkECMTypeValidity(ecmPropertyType) {
if (PropertyGroupTranslatorService.RECOGNISED_ECM_TYPES.indexOf(ecmPropertyType) === -1) {
this.logService.error(`Unknown type for mapping: ${ecmPropertyType}`);

View File

@@ -125,7 +125,7 @@ export class DocumentListService implements DocumentListLoader {
*/
getNode(nodeId: string, includeFields: string[] = []): Observable<NodeEntry> {
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', ...includeFields]
const includeFieldsRequest = ['path', 'properties', 'allowableOperations', 'permissions', 'definition', ...includeFields]
.filter((element, index, array) => index === array.indexOf(element));
const opts: any = {

View File

@@ -1,20 +1,22 @@
<div [attr.data-automation-id]="'card-select-label-' + property.key"
class="adf-property-label">{{ property.label | translate }}</div>
<div class="adf-property-field">
<div *ngIf="!isEditable()"
class="adf-select-item-padding adf-property-value"
data-automation-class="read-only-value">{{ property.displayValue | async }}</div>
<div *ngIf="isEditable()">
<mat-form-field class="adf-select-item-padding-editable adf-property-value">
<mat-select [(value)]="value"
(selectionChange)="onChange($event)"
data-automation-class="select-box">
<mat-option *ngIf="showNoneOption()">{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
<mat-option *ngFor="let option of getOptions() | async"
[value]="option.key">
{{ option.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<ng-container *ngIf="!property.isEmpty() || isEditable()">
<div [attr.data-automation-id]="'card-select-label-' + property.key"
class="adf-property-label">{{ property.label | translate }}</div>
<div class="adf-property-field">
<div *ngIf="!isEditable()"
class="adf-select-item-padding adf-property-value"
data-automation-class="read-only-value">{{ property.displayValue | async }}</div>
<div *ngIf="isEditable()">
<mat-form-field class="adf-select-item-padding-editable adf-property-value">
<mat-select [(value)]="value"
(selectionChange)="onChange($event)"
data-automation-class="select-box">
<mat-option *ngIf="showNoneOption()">{{ 'CORE.CARDVIEW.NONE' | translate }}</mat-option>
<mat-option *ngFor="let option of getOptions() | async"
[value]="option.key">
{{ option.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
</ng-container>

View File

@@ -37,6 +37,9 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
@Input()
displayNoneOption: boolean = true;
@Input()
displayEmpty: boolean = true;
value: string;
constructor(cardViewUpdateService: CardViewUpdateService) {
@@ -64,4 +67,8 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
showNoneOption() {
return this.displayNoneOption;
}
get showProperty(): boolean {
return this.displayEmpty || !this.property.isEmpty();
}
}

View File

@@ -16,6 +16,7 @@
*/
import { CardViewItemValidator } from './card-view-item-validator.interface';
import { Constraint } from '@alfresco/js-api';
export interface CardViewItemProperties {
label: string;
@@ -27,4 +28,5 @@ export interface CardViewItemProperties {
icon?: string;
validators?: CardViewItemValidator[];
data?: any;
constraints?: Constraint[];
}

7461
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -71,7 +71,7 @@
"process services-cloud"
],
"dependencies": {
"@alfresco/js-api": "3.9.0",
"@alfresco/js-api": "3.10.0-c1ad5d79a257f31a52ffd327022458da7926c211",
"@angular/animations": "^10.0.4",
"@angular/cdk": "10.0.2",
"@angular/common": "^10.0.4",