[ADF-4219] Multivalue Metadata Card View ()

* [ADF-4219] Multivalue Metadata  Card View

* [ADF-4219] Add documentation

* [ADF-4219] Improve code, docs and tests

* [ADF-4219] Fix e2e tests
This commit is contained in:
davidcanonieto 2019-04-17 17:04:27 +01:00 committed by Eugenio Romano
parent 21fd0299bd
commit 8395b0baa5
18 changed files with 217 additions and 24 deletions

@ -601,9 +601,10 @@
"content-metadata": {
"presets": {
"default": {
"exif:exif": "*"
"exif:exif": "*"
}
}
},
"multi-value-pipe-separator" : ", "
},
"sideNav": {
"expandedSidenav": true,

@ -162,6 +162,7 @@ for more information about installing and using the source code.
| [Text Highlight pipe](core/pipes/text-highlight.pipe.md) | Adds highlighting to words or sections of text that match a search string. | [Source](../lib/core/pipes/text-highlight.pipe.ts) |
| [Time Ago pipe](core/pipes/time-ago.pipe.md) | Converts a recent past date into a number of days ago. | [Source](../lib/core/pipes/time-ago.pipe.ts) |
| [User Initial pipe](core/pipes/user-initial.pipe.md) | Takes the name fields of a UserProcessModel object and extracts and formats the initials. | [Source](../lib/core/pipes/user-initial.pipe.ts) |
| [Multi value pipe](core/pipes/multi-value.pipe.md) | Takes a list of values to stringify them with a custom separator. | [Source](../lib/core/pipes/multi-value.pipe.ts) |
### Services

@ -274,3 +274,21 @@ example below shows this with an aspect-oriented config:
Nothing - since this aspect is not related to the node, it will simply be ignored and not
displayed. The aspects to be displayed are calculated as an intersection of the preset's aspects and the aspects related to the node.
## Multi value card properties
Multi value properties are displayed one after another separated by a comma. This card makes use of the [Multi Value Pipe](../../core/pipes/multi-value.pipe.ts).
To customize the separator used by this card you can set it in your `app.config.json` inside your content-metadata configuration:
```json
"content-metadata": {
"presets": {
"default": {
"includeAll": true,
"exclude": "exif:exif",
"exif:exif": [ "exif:pixelXDimension", "exif:pixelYDimension"]
}
},
"multi-value-pipe-separator" : " - "
},
```

@ -0,0 +1,39 @@
# [Multi Value Pipe](../../../lib/core/pipes/multi-value.pipe.ts "Defined in multi-value.pipe.ts")
Takes an array of strings and turns it into one string where items are separated by a separator. The default separator applied to the list is `', '`, however, you can set your own separator in the params of the pipe.
## Basic Usage
<!-- {% raw %} -->
### Default separator
```HTML
<div>
List {{ values | multiValue }}
</div>
```
#### Result
![multi-value-pipe](../../docassets/images/multi-value-default.pipe.png)
### Custom separator
```HTML
<div>
List {{ values | multiValue: ' :) ' }}
</div>
```
<!-- {% endraw %} -->
#### Result
![multi-value-pipe](../../docassets/images/multi-value.pipe.png)
## Details
The pipe gets every one of the items passed to the pipe and stringifies it adding the separator set in the configuration.
You will need to specify the separator you want to use for it to work.

Binary file not shown.

After

(image error) Size: 10 KiB

Binary file not shown.

After

(image error) Size: 11 KiB

@ -15,21 +15,21 @@
* limitations under the License.
*/
import TestConfig = require('../../test.config');
import TestConfig = require('../../../test.config');
import { LoginPage } from '@alfresco/adf-testing';
import { ViewerPage } from '../../pages/adf/viewerPage';
import { ContentServicesPage } from '../../pages/adf/contentServicesPage';
import { ViewerPage } from '../../../pages/adf/viewerPage';
import { ContentServicesPage } from '../../../pages/adf/contentServicesPage';
import CONSTANTS = require('../../util/constants');
import resources = require('../../util/resources');
import CONSTANTS = require('../../../util/constants');
import resources = require('../../../util/resources');
import { StringUtil } from '@alfresco/adf-testing';
import { FolderModel } from '../../models/ACS/folderModel';
import { AcsUserModel } from '../../models/ACS/acsUserModel';
import { FolderModel } from '../../../models/ACS/folderModel';
import { AcsUserModel } from '../../../models/ACS/acsUserModel';
import { AlfrescoApiCompatibility as AlfrescoApi } from '@alfresco/js-api';
import { UploadActions } from '../../actions/ACS/upload.actions';
import { UploadActions } from '../../../actions/ACS/upload.actions';
describe('Viewer', () => {

@ -33,7 +33,6 @@ import { AlfrescoApiCompatibility as AlfrescoApi } from '@alfresco/js-api';
import { UploadActions } from '../../../actions/ACS/upload.actions';
import { NavigationBarPage } from '../../..//pages/adf/navigationBarPage';
describe('Viewer', () => {
const viewerPage = new ViewerPage();

@ -104,6 +104,4 @@ describe('Viewer', () => {
});
});
});

@ -25,7 +25,9 @@ import {
CardViewDatetimeItemModel,
CardViewIntItemModel,
CardViewFloatItemModel,
LogService
LogService,
MultiValuePipe,
AppConfigService
} from '@alfresco/adf-core';
import { Property, CardViewGroup, OrganisedPropertyGroup } from '../interfaces/content-metadata.interfaces';
@ -46,7 +48,12 @@ export class PropertyGroupTranslatorService {
static readonly RECOGNISED_ECM_TYPES = [D_TEXT, D_MLTEXT, D_DATE, D_DATETIME, D_INT, D_LONG, D_FLOAT, D_DOUBLE, D_BOOLEAN];
constructor(private logService: LogService) {
valueSeparator: string;
constructor(private logService: LogService,
private multiValuePipe: MultiValuePipe,
private appConfig: AppConfigService) {
this.valueSeparator = this.appConfig.get<string>('content-metadata.multi-value-pipe-separator');
}
public translateToCardViewGroups(propertyGroups: OrganisedPropertyGroup[], propertyValues): CardViewGroup[] {
@ -115,7 +122,9 @@ export class PropertyGroupTranslatorService {
case D_TEXT:
default:
cardViewItemProperty = new CardViewTextItemModel(Object.assign(propertyDefinition, {
multiline: false
multivalued: property.multiValued,
multiline: property.multiValued,
pipes: [{ pipe: this.multiValuePipe, params: [this.valueSeparator]}]
}));
}

@ -859,6 +859,10 @@
]
}
}
},
"multi-value-pipe-separator": {
"description": "Content metadata's separator for multi value properties",
"type": "string"
}
}
},

@ -18,6 +18,7 @@
import { Component, Input, OnChanges, ViewChild } from '@angular/core';
import { CardViewTextItemModel } from '../../models/card-view-textitem.model';
import { CardViewUpdateService } from '../../services/card-view-update.service';
import { AppConfigService } from '../../../app-config/app-config.service';
@Component({
selector: 'adf-card-view-textitem',
@ -25,6 +26,9 @@ import { CardViewUpdateService } from '../../services/card-view-update.service';
styleUrls: ['./card-view-textitem.component.scss']
})
export class CardViewTextItemComponent implements OnChanges {
static DEFAULT_SEPARATOR = ', ';
@Input()
property: CardViewTextItemModel;
@ -40,12 +44,15 @@ export class CardViewTextItemComponent implements OnChanges {
inEdit: boolean = false;
editedValue: string;
errorMessages: string[];
valueSeparator: string;
constructor(private cardViewUpdateService: CardViewUpdateService) {
constructor(private cardViewUpdateService: CardViewUpdateService,
private appConfig: AppConfigService) {
this.valueSeparator = this.appConfig.get<string>('content-metadata.multi-value-pipe-separator') || CardViewTextItemComponent.DEFAULT_SEPARATOR;
}
ngOnChanges(): void {
this.editedValue = this.property.value;
this.editedValue = this.property.multiline ? this.property.displayValue : this.property.value;
}
showProperty(): boolean {
@ -78,20 +85,29 @@ export class CardViewTextItemComponent implements OnChanges {
}
reset(): void {
this.editedValue = this.property.value;
this.editedValue = this.property.multiline ? this.property.displayValue : this.property.value;
this.setEditMode(false);
}
update(): void {
if (this.property.isValid(this.editedValue)) {
this.cardViewUpdateService.update(this.property, this.editedValue);
this.property.value = this.editedValue;
const updatedValue = this.prepareValueForUpload(this.property, this.editedValue);
this.cardViewUpdateService.update(this.property, updatedValue);
this.property.value = updatedValue;
this.setEditMode(false);
} else {
this.errorMessages = this.property.getValidationErrors(this.editedValue);
}
}
prepareValueForUpload(property: CardViewTextItemModel, value: string): string | string [] {
const listOfValues = value;
if (property.multivalued) {
return listOfValues.split(this.valueSeparator);
}
return listOfValues;
}
onTextAreaInputChange() {
this.errorMessages = this.property.getValidationErrors(this.editedValue);
}

@ -20,6 +20,7 @@ import { CardViewTextItemPipeProperty } from './card-view-textitem-pipe-property
export interface CardViewTextItemProperties extends CardViewItemProperties {
multiline?: boolean;
multivalued?: boolean;
pipes?: CardViewTextItemPipeProperty[];
clickCallBack?: any;
}

@ -23,12 +23,14 @@ import { CardViewTextItemPipeProperty, CardViewTextItemProperties } from '../int
export class CardViewTextItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
type: string = 'text';
multiline?: boolean;
multivalued?: boolean;
pipes?: CardViewTextItemPipeProperty[];
clickCallBack?: any;
constructor(cardViewTextItemProperties: CardViewTextItemProperties) {
super(cardViewTextItemProperties);
this.multiline = !!cardViewTextItemProperties.multiline;
this.multivalued = !!cardViewTextItemProperties.multivalued;
this.pipes = cardViewTextItemProperties.pipes || [];
this.clickCallBack = cardViewTextItemProperties.clickCallBack ? cardViewTextItemProperties.clickCallBack : null;
}

@ -0,0 +1,66 @@
/*!
* @license
* Copyright 2019 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 { MultiValuePipe } from './multi-value.pipe';
import { TestBed } from '@angular/core/testing';
import { setupTestBed } from 'core';
import { CoreTestingModule } from 'core/testing/core.testing.module';
describe('FullNamePipe', () => {
let pipe: MultiValuePipe;
setupTestBed({
imports: [CoreTestingModule]
});
beforeEach(() => {
pipe = TestBed.get(MultiValuePipe);
});
it('should add the separator when a list is provided', () => {
const values = ['cat', 'house', 'dog'];
expect(pipe.transform(values)).toBe('cat, house, dog');
});
it('should add custom separator when set', () => {
const values = ['cat', 'house', 'dog'];
const customSeparator = ' - ';
expect(pipe.transform(values, customSeparator)).toBe('cat - house - dog');
});
it('should not add separator when the list has only one item', () => {
const values = ['cat'];
expect(pipe.transform(values)).toBe('cat');
});
it('should return empty string when an empty list is passed', () => {
const values = [];
expect(pipe.transform(values)).toBe('');
});
it('should return empty string when an empty string is passed', () => {
const values = '';
expect(pipe.transform(values)).toBe('');
});
it('should return same string when the value passed is a string', () => {
const values = 'cat';
expect(pipe.transform(values)).toBe('cat');
});
});

@ -0,0 +1,34 @@
/*!
* @license
* Copyright 2019 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 { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'multiValue' })
export class MultiValuePipe implements PipeTransform {
static DEFAULT_SEPARATOR = ', ';
transform(values: string | string [], valueSeparator: string = MultiValuePipe.DEFAULT_SEPARATOR): string {
if (values && values instanceof Array) {
values.map((value) => value.trim());
return values.join(valueSeparator);
}
return <string> values;
}
}

@ -27,6 +27,7 @@ import { InitialUsernamePipe } from './user-initial.pipe';
import { FullNamePipe } from './full-name.pipe';
import { FormatSpacePipe } from './format-space.pipe';
import { FileTypePipe } from './file-type.pipe';
import { MultiValuePipe } from './multi-value.pipe';
@NgModule({
imports: [
@ -41,7 +42,8 @@ import { FileTypePipe } from './file-type.pipe';
FullNamePipe,
NodeNameTooltipPipe,
FormatSpacePipe,
FileTypePipe
FileTypePipe,
MultiValuePipe
],
providers: [
FileSizePipe,
@ -51,7 +53,8 @@ import { FileTypePipe } from './file-type.pipe';
InitialUsernamePipe,
NodeNameTooltipPipe,
FormatSpacePipe,
FileTypePipe
FileTypePipe,
MultiValuePipe
],
exports: [
FileSizePipe,
@ -62,7 +65,8 @@ import { FileTypePipe } from './file-type.pipe';
FullNamePipe,
NodeNameTooltipPipe,
FormatSpacePipe,
FileTypePipe
FileTypePipe,
MultiValuePipe
]
})
export class PipeModule {

@ -22,5 +22,6 @@ export * from './text-highlight.pipe';
export * from './time-ago.pipe';
export * from './user-initial.pipe';
export * from './full-name.pipe';
export * from './multi-value.pipe';
export * from './pipe.module';