Skip to content

Commit

Permalink
[ADF-5316] - fix unit test #2
Browse files Browse the repository at this point in the history
  • Loading branch information
Vito Albano committed Feb 1, 2021
1 parent ff8bba0 commit 0a0542a
Show file tree
Hide file tree
Showing 19 changed files with 450 additions and 185 deletions.
86 changes: 86 additions & 0 deletions docs/content-services/components/content-type-dialog.component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
Title: Content Type Dialog component
Added: v2.0.0
Status: Active
Last reviewed: 2021-01-20
---

# [Content Type Dialog component](../../../lib/content-services/src/lib/content-type/content-type-dialog.component.ts "Defined in content-type-dialog.component.ts")

Confirm dialog when user changes content type of a node.

## Details

The [Content Type Dialog component](content-type-dialog.component.md) works as a dialog showing a confirm message when the user changes the conten type of a node. It is showing the properties of the new content type selected.

### Showing the dialog

Unlike most components, the [Content Type Dialog component](content-type-dialog.component.md) is typically shown in a dialog box
rather than the main page and you are responsible for opening the dialog yourself. You can use the
[Angular Material Dialog](https://material.angular.io/components/dialog/overview) for this,
as shown in the usage example. ADF provides the [`ContentTypeDialogComponentData`](../../../lib/content-services/src/lib/content-type/content-type-metadata.interface.ts) interface
to work with the Dialog's
[data option](https://material.angular.io/components/dialog/overview#sharing-data-with-the-dialog-component-):

```ts
export interface ContentTypeDialogComponentData {
title: string;
description: string;
confirmMessage: string;
select: Subject<boolean>;
nodeType?: string;
}
```

The properties are described in the table below:

| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| title | `string` | "" | Dialog title |
| description | `string` | "" | Text to appear as description under the dialog title |
| confirmMessage | `string` | "" | Text that will be showed on the top of properties list accordion |
| select | [`Subject<Node>`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/Node.md) | | Event emitted when apply button is clicked |
| nodeType | `string` | "" | current prefixed name of the content type selected |

If you don't want to manage the dialog yourself then it is easier to use the
methods of the Content Type Property Service, which create
the dialog for you.

### Usage example

```ts
import { MatDialog } from '@angular/material/dialog';
import { AspectListDialogComponentData, AspectListDialogComponent} from '@adf/content-services'
import { Subject } from 'rxjs/Subject';
...
constructor(dialog: MatDialog ... ) {}
openSelectorDialog() {
const data: ContentTypeDialogComponentData = {
title: 'CORE.METADATA.CONTENT_TYPE.DIALOG.TITLE',
description: 'CORE.METADATA.CONTENT_TYPE.DIALOG.DESCRIPTION',
confirmMessage: 'CORE.METADATA.CONTENT_TYPE.DIALOG.CONFIRM',
select: select,
nodeType
};
this.dialog.open(
ContentTypeDialogComponent,
{
data, panelClass: 'adf-content-type-dialog',
width: '630px'
}
);
data.select.subscribe((selections: Node[]) => {
// Use or store selection...
},
(error)=>{
//your error handling
},
()=>{
//action called when an action or cancel is clicked on the dialog
this.dialog.closeAll();
});
}
```

All the results will be streamed to the select [subject](http://reactivex.io/rxjs/manual/overview.html#subject) present in the [`ContentTypeDialogData`](../../../lib/content-services/src/lib/content-type/content-type-metadata.interface.ts) object passed to the dialog.
When the dialog action is selected by clicking, the `data.select` stream will be completed.
6 changes: 3 additions & 3 deletions lib/cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"dist": "rm -rf ./dist/ && npm run build && cp -R ./bin ./dist/ && cp -R ./resources ./dist && cp -R ./templates ./dist && cp ./package.json ./dist/"
},
"dependencies": {
"@alfresco/js-api": "4.3.0-61350fee919fbeb2b6c949621161b6b076d44133",
"@alfresco/js-api": " 4.3.0-2e84309af123ae96cc85bd9683cb1ab9a7119c33",
"commander": "^4.0.0",
"ejs": "^2.6.1",
"license-checker": "^25.0.1",
Expand Down
2 changes: 1 addition & 1 deletion lib/content-services/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@angular/forms": ">=10.0.2",
"@angular/material": ">=10.0.1",
"@angular/router": ">=10.0.2",
"@alfresco/js-api": "4.2.0",
"@alfresco/js-api": " 4.3.0-2e84309af123ae96cc85bd9683cb1ab9a7119c33",
"@alfresco/adf-core": "4.2.0",
"@ngx-translate/core": ">=13.0.0",
"moment": ">=2.22.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('ContentMetadataComponent', () => {
node = <Node> {
id: 'node-id',
aspectNames: [],
nodeType: '',
nodeType: 'cm:node',
content: {},
properties: {},
createdByUser: {},
Expand Down Expand Up @@ -170,6 +170,29 @@ describe('ContentMetadataComponent', () => {
saveButton.nativeElement.click();
fixture.detectChanges();
}));

it('should open the confirm dialgo when content type is changed', fakeAsync(async () => {
component.editable = true;
const property = <CardViewBaseItemModel> { key: 'nodeType', value: 'ft:sbiruli' };
const expectedNode = Object.assign({}, node, { nodeType: 'ft:sbiruli' });
spyOn(contentMetadataService, 'openConfirmDialog').and.returnValue(of(true));
spyOn(nodesApiService, 'updateNode').and.callFake(() => {
return of(expectedNode);
});

updateService.update(property, 'ft:poppoli');
tick(600);

fixture.detectChanges();
await fixture.whenStable();
const saveButton = fixture.debugElement.query(By.css('[data-automation-id="save-metadata"]'));
saveButton.nativeElement.click();

await fixture.whenStable();
expect(component.node).toEqual(expectedNode);
expect(contentMetadataService.openConfirmDialog).toHaveBeenCalledWith({nodeType: 'ft:poppoli'});
expect(nodesApiService.updateNode).toHaveBeenCalled();
}));
});

describe('Reseting', () => {
Expand Down Expand Up @@ -206,6 +229,7 @@ describe('ContentMetadataComponent', () => {

component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });

expect(contentMetadataService.getNodeType).toHaveBeenCalledWith(node.nodeType);
expect(contentMetadataService.getBasicProperties).toHaveBeenCalledWith(expectedNode);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ import { ContentMetadataService } from './content-metadata.service';
import { of } from 'rxjs';
import { PropertyGroup } from '../interfaces/property-group.interface';
import { TranslateModule } from '@ngx-translate/core';
import { ContentTypePropertiesService } from './content-type-property.service';

describe('ContentMetaDataService', () => {

let service: ContentMetadataService;
let classesApi: ClassesApi;
let appConfig: AppConfigService;
let contentPropertyService: ContentTypePropertiesService;

const exifResponse: PropertyGroup = {
name: 'exif:exif',
Expand Down Expand Up @@ -64,6 +66,7 @@ describe('ContentMetaDataService', () => {

beforeEach(() => {
service = TestBed.inject(ContentMetadataService);
contentPropertyService = TestBed.inject(ContentTypePropertiesService);
const alfrescoApiService = TestBed.inject(AlfrescoApiService);
classesApi = alfrescoApiService.classesApi;
appConfig = TestBed.inject(AppConfigService);
Expand All @@ -89,6 +92,28 @@ describe('ContentMetaDataService', () => {
);
});

it('should return the content type property', () => {
spyOn(contentPropertyService, 'getContentTypeCardItem').and.returnValue(of({ label: 'hello i am a weird content type'}));

service.getNodeType('fn:fakenode').subscribe(
(res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.label).toBe('hello i am a weird content type');
}
);
});

it('should trigger the opening of the content type dialog', () => {
spyOn(contentPropertyService, 'openContentTypeDialogConfirm').and.returnValue(of());

service.openConfirmDialog('fn:fakenode').subscribe(
() => {
expect(contentPropertyService.openContentTypeDialogConfirm).toHaveBeenCalledWith('fn:fakenode');
}
);
});

describe('AspectOriented preset', () => {

it('should return response with exif property', (done) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*!
* @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 { Node } from '@alfresco/js-api';
import { TestBed } from '@angular/core/testing';
import { ContentMetadataService } from './content-metadata.service';
import { of } from 'rxjs';
import { ContentTypePropertiesService } from './content-type-property.service';

describe('ContentMetaDataService', () => {

let service: ContentMetadataService;
let contentPropertyService: ContentTypePropertiesService;

beforeEach(() => {
service = TestBed.inject(ContentMetadataService);
contentPropertyService = TestBed.inject(ContentTypePropertiesService);
});

it('should return all the properties of the node', () => {
const fakeNode: Node = <Node> {
name: 'Node',
id: 'fake-id',
isFile: true,
aspectNames: ['exif:exif'],
createdByUser: {displayName: 'test-user'},
modifiedByUser: {displayName: 'test-user-modified'}
};

service.getBasicProperties(fakeNode).subscribe(
(res) => {
expect(res.length).toEqual(10);
expect(res[0].value).toEqual('Node');
expect(res[1].value).toBeFalsy();
expect(res[2].value).toBe('test-user');
}
);
});

it('should return the content type property', () => {
spyOn(contentPropertyService, 'getContentTypeCardItem').and.returnValue(of({ label: 'hello i am a weird content type'}));

service.getNodeType('fn:fakenode').subscribe(
(res: any) => {
expect(res).toBeDefined();
expect(res).not.toBeNull();
expect(res.label).toBe('hello i am a weird content type');
}
);
});

it('should trigger the opening of the content type dialog', () => {
spyOn(contentPropertyService, 'openContentTypeDialogConfirm').and.returnValue(of());

service.openConfirmDialog('fn:fakenode').subscribe(
() => {
expect(contentPropertyService.openContentTypeDialogConfirm).toHaveBeenCalledWith('fn:fakenode');
}
);
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ export class ContentTypePropertiesService {
private contentTypesOptions$: Observable<CardViewSelectItemOption<string>[]>;

constructor(private contentTypeService: ContentTypeService, private dialog: MatDialog) {
this.contentTypesOptions$ = this.getContentTypesAsSelectOption();
}

getContentTypeCardItem(nodeType: string): Observable<CardViewItem[]> {
this.contentTypesOptions$ = this.getContentTypesAsSelectOption(nodeType);
return this.contentTypeService.getContentTypeByPrefix(nodeType).
pipe(
map((contentType) => {
Expand All @@ -49,8 +49,8 @@ export class ContentTypePropertiesService {
}));
}

private getContentTypesAsSelectOption(): Observable<CardViewSelectItemOption<string>[]> {
return this.contentTypeService.getContentTypes().pipe(
private getContentTypesAsSelectOption(nodeType: string): Observable<CardViewSelectItemOption<string>[]> {
return this.contentTypeService.getContentTypeChildren(nodeType).pipe(
map((contentTypesEntries) => {
return contentTypesEntries.map((contentType) => <CardViewSelectItemOption<string>> { key: contentType.entry.id, label: contentType.entry.title });
}));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,45 @@
<div class="adf-content-type-dialog">
<h2 mat-dialog-title class="adf-content-type-dialog-title" data-automation-id="adf-content-type-dialog-title">{{title | translate}}</h2>
<mat-dialog-content class="mat-typography" class="adf-content-type-dialog-content" data-automation-id="adf-content-type-dialog-content">
<h4>{{description | translate}}</h4>
<p>{{confirmMessage | translate}}</p>
<mat-accordion >
<mat-expansion-panel class="adf-content-type-accordion">
<mat-expansion-panel-header>
<mat-panel-title>
{{'CORE.METADATA.CONTENT_TYPE.DIALOG.VIEW_DETAILS' | translate}}
</mat-panel-title>
</mat-expansion-panel-header>
<table mat-table [dataSource]="currentContentType?.entry?.properties"
*ngIf="currentContentType?.entry?.properties?.length > 0" class="adf-content-type-table" >
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> {{'CORE.METADATA.CONTENT_TYPE.DIALOG.PROPERTY.NAME' | translate}} </th>
<td mat-cell *matCellDef="let property"> {{property.id}} </td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef> {{'CORE.METADATA.CONTENT_TYPE.DIALOG.PROPERTY.DESCRIPTION' | translate}} </th>
<td mat-cell *matCellDef="let property"> {{property.title}} </td>
</ng-container>
<ng-container matColumnDef="dataType">
<th mat-header-cell *matHeaderCellDef> {{'CORE.METADATA.CONTENT_TYPE.DIALOG.PROPERTY.DATA_TYPE' | translate}} </th>
<td mat-cell *matCellDef="let property"> {{property.dataType}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="propertyColumns"></tr>
<tr mat-row *matRowDef="let row; columns: propertyColumns;"></tr>
</table>
</mat-expansion-panel>
</mat-accordion>
<h2 mat-dialog-title class="adf-content-type-dialog-title" data-automation-id="content-type-dialog-title">{{title |
translate}}</h2>
<mat-dialog-content class="mat-typography" class="adf-content-type-dialog-content"
data-automation-id="content-type-dialog-content">
<h4 data-automation-id="content-type-dialog-description">{{description | translate}}</h4>
<p data-automation-id="content-type-dialog-confirm-message">{{confirmMessage | translate}}</p>
<mat-accordion>
<mat-expansion-panel class="adf-content-type-accordion">
<mat-expansion-panel-header>
<mat-panel-title>
{{'CORE.METADATA.CONTENT_TYPE.DIALOG.VIEW_DETAILS' | translate}}
</mat-panel-title>
</mat-expansion-panel-header>
<table mat-table [dataSource]="currentContentType?.entry?.properties"
*ngIf="currentContentType?.entry?.properties?.length > 0" class="adf-content-type-table">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> {{'CORE.METADATA.CONTENT_TYPE.DIALOG.PROPERTY.NAME' |
translate}} </th>
<td mat-cell *matCellDef="let property"> {{property.id}} </td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef>
{{'CORE.METADATA.CONTENT_TYPE.DIALOG.PROPERTY.DESCRIPTION' | translate}} </th>
<td mat-cell *matCellDef="let property"> {{property.title}} </td>
</ng-container>
<ng-container matColumnDef="dataType">
<th mat-header-cell *matHeaderCellDef> {{'CORE.METADATA.CONTENT_TYPE.DIALOG.PROPERTY.DATA_TYPE'
| translate}} </th>
<td mat-cell *matCellDef="let property"> {{property.dataType}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="propertyColumns"></tr>
<tr mat-row *matRowDef="let row; columns: propertyColumns;"></tr>
</table>
</mat-expansion-panel>
</mat-accordion>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>{{'CORE.METADATA.CONTENT_TYPE.DIALOG.CANCEL' | translate }}</button>
<button mat-button class="adf-content-type-dialog-apply-button"
[mat-dialog-close]="true" cdkFocusInitial (click)="onApply()">{{'CORE.METADATA.CONTENT_TYPE.DIALOG.APPLY' | translate}}</button>
<button mat-button mat-dialog-close
id="conten-type-dialog-actions-cancel">{{'CORE.METADATA.CONTENT_TYPE.DIALOG.CANCEL' | translate }}</button>
<button mat-button class="adf-content-type-dialog-apply-button" id="content-type-dialog-apply-button"
[mat-dialog-close]="true" cdkFocusInitial (click)="onApply()">{{'CORE.METADATA.CONTENT_TYPE.DIALOG.APPLY' |
translate}}</button>
</mat-dialog-actions>
</div>

0 comments on commit 0a0542a

Please sign in to comment.