[ACS-6252] support disabling the tags and categories feature in the applications (#9106)

* ACS-6252 Added rules field to SearchCategory interface

* ACS-6252 Hide aspects related with tags and categories if tags and categories features  are disabled

* ACS-6252 Return from services information if tags and categories are disabled

* ACS-6252 Unit tests for changes in AspectListDialogComponent

* ACS-6252 Unit tests for changes for AspectListComponent

* ACS-6252 Unit tests for DialogAspectListService

* ACS-6252 Unit tests for changes for TagService and CategoryService

* ACS-6252 Updated documentation for changes

* ACS-6252 Fixed imports formatting

* ACS-6252 Fix after rebasing

* ACS-6252 Addressed PR comments

* ACS-6252 Excluded e2es
This commit is contained in:
AleksanderSklorz 2023-11-28 11:41:32 +01:00 committed by GitHub
parent 979bf3ac59
commit 7793aba89e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 337 additions and 154 deletions

View File

@ -29,6 +29,7 @@ export interface AspectListDialogComponentData {
overTableMessage: string;
select: Subject<string[]>;
nodeId?: string;
excludedAspects?: string[];
}
```
@ -41,6 +42,7 @@ The properties are described in the table below:
| overTableMessage | `string` | "" | Text that will be showed on the top of the aspect list table |
| select | [`Subject<Node>`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/Node.md) | | Event emitted with the current node selection when the dialog closes |
| nodeId | `string` | "" | Identifier of a node to apply aspects to. |
| excludedAspects | `string[]` | undefined | List of aspects' ids which should not be displayed. |
If you don't want to manage the dialog yourself then it is easier to use the
[Aspect List component](aspect-list.component.md), or the

View File

@ -30,6 +30,7 @@ The aspect are filtered via the app.config.json in this way :
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| nodeId | `string` | "" | Node Id of the node that we want to update |
| excludedAspects | `string[]` | undefined | List of aspects' ids which should not be displayed. |
### Events

View File

@ -65,6 +65,9 @@ Manages categories in Content Services.
- _nodeId:_ `string` - The identifier of a node.
- _categoryLinkBodyCreate:_ [`CategoryLinkBody[]`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/api/content-rest-api/docs/CategoryLinkBody.md) - Categories that node will be linked to.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`CategoryPaging`]((https://github.com/Alfresco/alfresco-js-api/blob/master/src/api/content-rest-api/docs/CategoryPaging.md))` | `[`CategoryEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/api/content-rest-api/docs/CategoryEntry.md)`>` - Categories that node has been linked to.
- **areCategoriesEnabled**():`boolean`<br/>
Checks if categories plugin is enabled.
- **Returns** `boolean` - true if categories plugin is enabled, false otherwise.
## Details

View File

@ -62,6 +62,9 @@ Manages tags in Content Services.
- _tagId:_ `string` - The identifier of a tag.
- _tagBody:_ `TagBody` - The updated tag.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`TagEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/TagEntry.md)`>` - Updated tag.
- **areTagsEnabled**():`boolean`<br/>
Checks if tags plugin is enabled.
- **Returns** `boolean` - true if tags plugin is enabled, false otherwise.
## Details

View File

@ -277,6 +277,9 @@ export interface SearchCategory {
selector: string;
settings: SearchWidgetSettings;
};
rules?: {
visible: string;
};
}
```

View File

@ -19,5 +19,10 @@
"C279971": "https://alfresco.atlassian.net/browse/ACS-6233",
"C279972": "https://alfresco.atlassian.net/browse/ACS-6233",
"C260181": "https://alfresco.atlassian.net/browse/ACS-6233",
"C297692": "https://alfresco.atlassian.net/browse/ACS-6244"
"C297692": "https://alfresco.atlassian.net/browse/ACS-6244",
"C260418": "https://alfresco.atlassian.net/browse/ACS-6425",
"C268070": "https://alfresco.atlassian.net/browse/ACS-6425",
"C272812": "https://alfresco.atlassian.net/browse/ACS-6425",
"C274704": "https://alfresco.atlassian.net/browse/ACS-6425",
"C311425": "https://alfresco.atlassian.net/browse/ACS-6425"
}

View File

@ -23,4 +23,5 @@ export interface AspectListDialogComponentData {
overTableMessage: string;
select: Subject<string[]>;
nodeId?: string;
excludedAspects?: string[];
}

View File

@ -9,7 +9,7 @@
{{'ADF-ASPECT-LIST.DIALOG.SELECTED' | translate}}</p>
</div>
<mat-dialog-content class="adf-aspect-dialog-content">
<adf-aspect-list #aspectList (valueChanged)="onValueChanged($event)" [nodeId]="currentNodeId">
<adf-aspect-list #aspectList (valueChanged)="onValueChanged($event)" [nodeId]="currentNodeId" [excludedAspects]="data.excludedAspects">
</adf-aspect-list>
</mat-dialog-content>

View File

@ -26,6 +26,8 @@ import { AspectListService } from './services/aspect-list.service';
import { delay } from 'rxjs/operators';
import { AspectEntry, Node } from '@alfresco/js-api';
import { NodesApiService } from '../common/services/nodes-api.service';
import { By } from '@angular/platform-browser';
import { AspectListComponent } from './aspect-list.component';
const aspectListMock: AspectEntry[] = [
{
@ -103,35 +105,35 @@ describe('AspectListDialogComponent', () => {
keyCode: 27
} as KeyboardEventInit);
describe('Without passing node id', () => {
beforeEach(async () => {
data = {
title: 'Title',
description: 'Description that can be longer or shorter',
overTableMessage: 'Over here',
select: new Subject<string[]>()
};
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ContentTestingModule, MatDialogModule],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data },
{
provide: MatDialogRef,
useValue: {
keydownEvents: () => of(event),
backdropClick: () => of(null),
close: jasmine.createSpy('close')
}
beforeEach(async () => {
data = {
title: 'Title',
description: 'Description that can be longer or shorter',
overTableMessage: 'Over here',
select: new Subject<string[]>(),
excludedAspects: []
};
await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ContentTestingModule, MatDialogModule],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data },
{
provide: MatDialogRef,
useValue: {
keydownEvents: () => of(event),
backdropClick: () => of(null),
close: jasmine.createSpy('close')
}
]
}).compileComponents();
});
}
]
}).compileComponents();
fixture = TestBed.createComponent(AspectListDialogComponent);
});
describe('Without passing node id', () => {
beforeEach(() => {
aspectListService = TestBed.inject(AspectListService);
spyOn(aspectListService, 'getAspects').and.returnValue(of(aspectListMock));
fixture = TestBed.createComponent(AspectListDialogComponent);
fixture.detectChanges();
});
@ -243,32 +245,7 @@ describe('AspectListDialogComponent', () => {
describe('Passing the node id', () => {
beforeEach(async () => {
data = {
title: 'Title',
description: 'Description that can be longer or shorter',
overTableMessage: 'Over here',
select: new Subject<string[]>(),
nodeId: 'fake-node-id'
};
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ContentTestingModule, MatDialogModule],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data },
{
provide: MatDialogRef,
useValue: {
close: jasmine.createSpy('close'),
keydownEvents: () => of(event),
backdropClick: () => of(null)
}
}
]
});
await TestBed.compileComponents();
});
beforeEach(async () => {
data.nodeId = 'fake-node-id';
aspectListService = TestBed.inject(AspectListService);
nodeService = TestBed.inject(NodesApiService);
spyOn(aspectListService, 'getAspects').and.returnValue(of([...aspectListMock, ...customAspectListMock]));
@ -278,7 +255,6 @@ describe('AspectListDialogComponent', () => {
of(new Node({ id: 'fake-node-id', aspectNames: ['frs:AspectOne', 'cst:customAspect'] })).pipe(delay(0))
);
fixture = TestBed.createComponent(AspectListDialogComponent);
fixture.componentInstance.data.select = new Subject<string[]>();
fixture.detectChanges();
await fixture.whenStable();
});
@ -328,4 +304,14 @@ describe('AspectListDialogComponent', () => {
expect(applyButton.disabled).toBe(false);
});
});
describe('AspectListComponent', () => {
it('should have set excludedAspects from dialog data', () => {
data.excludedAspects = ['some aspect 1', 'some aspect 2'];
fixture.detectChanges();
expect(fixture.debugElement.query(By.directive(AspectListComponent)).componentInstance.excludedAspects)
.toBe(data.excludedAspects);
});
});
});

View File

@ -21,9 +21,8 @@ import { ContentTestingModule } from '../testing/content.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { AspectListComponent } from './aspect-list.component';
import { AspectListService } from './services/aspect-list.service';
import { of } from 'rxjs';
import { EMPTY, of } from 'rxjs';
import { AspectEntry } from '@alfresco/js-api';
import { delay } from 'rxjs/operators';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatExpansionPanelHarness } from '@angular/material/expansion/testing';
@ -136,9 +135,8 @@ describe('AspectListComponent', () => {
});
it('should show the loading spinner when result is loading', async () => {
const delayResult = of(null).pipe(delay(0));
spyOn(nodeService, 'getNode').and.returnValue(delayResult);
spyOn(aspectListService, 'getAspects').and.returnValue(delayResult);
spyOn(nodeService, 'getNode').and.returnValue(EMPTY);
spyOn(aspectListService, 'getAspects').and.returnValue(EMPTY);
fixture.detectChanges();
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
@ -156,7 +154,6 @@ describe('AspectListComponent', () => {
nodeService = TestBed.inject(NodesApiService);
spyOn(nodeService, 'getNode').and.returnValue(of({ id: 'fake-node-id', aspectNames: ['frs:AspectOne'] } as any));
component.nodeId = 'fake-node-id';
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
@ -164,89 +161,105 @@ describe('AspectListComponent', () => {
fixture.destroy();
});
it('should return true when same aspect list selected', () => {
expect(component.hasEqualAspect).toBe(true);
describe('without excluding aspects', () => {
beforeEach(() => {
fixture.detectChanges();
});
it('should return true when same aspect list selected', () => {
expect(component.hasEqualAspect).toBe(true);
});
it('should return false when different aspect list selected', () => {
component.clear();
expect(component.hasEqualAspect).toBe(false);
});
it('should show all the aspects', async () => {
expect(await loader.hasHarness(MatExpansionPanelHarness.with({selector: '#aspect-list-FirstAspect'}))).toBe(true);
expect(await loader.hasHarness(MatExpansionPanelHarness.with({selector: '#aspect-list-SecondAspect'}))).toBe(true);
});
it('should show aspect id when name or title is not set', () => {
const noNameAspect = fixture.nativeElement.querySelector('#aspect-list-cst-nonamedAspect .adf-aspect-list-element-title');
expect(noNameAspect).toBeDefined();
expect(noNameAspect).not.toBeNull();
expect(noNameAspect.innerText).toBe('cst:nonamedAspect');
});
it('should show the details when a row is clicked', async () => {
const panel = await loader.getHarness(MatExpansionPanelHarness);
await panel.expand();
expect(await panel.getDescription()).not.toBeNull();
const table = await panel.getHarness(MatTableHarness);
const [row1, row2] = await table.getRows();
const [r1c1, r1c2, r1c3] = await row1.getCells();
expect(await r1c1.getText()).toBe('channelPassword');
expect(await r1c2.getText()).toBe('The authenticated channel password');
expect(await r1c3.getText()).toBe('d:propA');
const [r2c1, r2c2, r2c3] = await row2.getCells();
expect(await r2c1.getText()).toBe('channelUsername');
expect(await r2c2.getText()).toBe('The authenticated channel username');
expect(await r2c3.getText()).toBe('d:propB');
});
it('should show as checked the node properties', async () => {
const panel = await loader.getHarness(MatExpansionPanelHarness);
await panel.expand();
const checkbox = await panel.getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(true);
});
it('should remove aspects unchecked', async () => {
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
await panel[1].expand();
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(false);
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(2);
expect(component.nodeAspects[1]).toBe('frs:SecondAspect');
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(1);
expect(component.nodeAspects[0]).toBe('frs:AspectOne');
});
it('should reset the properties on reset', async () => {
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
await panel[1].expand();
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(false);
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(2);
component.reset();
expect(component.nodeAspects.length).toBe(1);
});
it('should clear all the properties on clear', async () => {
expect(component.nodeAspects.length).toBe(1);
component.clear();
expect(component.nodeAspects.length).toBe(0);
});
});
it('should return false when different aspect list selected', () => {
component.clear();
expect(component.hasEqualAspect).toBe(false);
});
describe('with excluded aspects', () => {
it('should not show aspect if it is excluded aspect', () => {
component.excludedAspects = ['cst:nonamedAspect'];
it('should show all the aspects', async () => {
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-FirstAspect' }))).toBe(true);
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-SecondAspect' }))).toBe(true);
});
it('should show aspect id when name or title is not set', () => {
const noNameAspect = fixture.nativeElement.querySelector('#aspect-list-cst-nonamedAspect .adf-aspect-list-element-title');
expect(noNameAspect).toBeDefined();
expect(noNameAspect).not.toBeNull();
expect(noNameAspect.innerText).toBe('cst:nonamedAspect');
});
it('should show the details when a row is clicked', async () => {
const panel = await loader.getHarness(MatExpansionPanelHarness);
await panel.expand();
expect(await panel.getDescription()).not.toBeNull();
const table = await panel.getHarness(MatTableHarness);
const [row1, row2] = await table.getRows();
const [r1c1, r1c2, r1c3] = await row1.getCells();
expect(await r1c1.getText()).toBe('channelPassword');
expect(await r1c2.getText()).toBe('The authenticated channel password');
expect(await r1c3.getText()).toBe('d:propA');
const [r2c1, r2c2, r2c3] = await row2.getCells();
expect(await r2c1.getText()).toBe('channelUsername');
expect(await r2c2.getText()).toBe('The authenticated channel username');
expect(await r2c3.getText()).toBe('d:propB');
});
it('should show as checked the node properties', async () => {
const panel = await loader.getHarness(MatExpansionPanelHarness);
await panel.expand();
const checkbox = await panel.getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(true);
});
it('should remove aspects unchecked', async () => {
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
await panel[1].expand();
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(false);
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(2);
expect(component.nodeAspects[1]).toBe('frs:SecondAspect');
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(1);
expect(component.nodeAspects[0]).toBe('frs:AspectOne');
});
it('should reset the properties on reset', async () => {
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
await panel[1].expand();
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(false);
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(2);
component.reset();
expect(component.nodeAspects.length).toBe(1);
});
it('should clear all the properties on clear', async () => {
expect(component.nodeAspects.length).toBe(1);
component.clear();
expect(component.nodeAspects.length).toBe(0);
fixture.detectChanges();
expect(fixture.nativeElement.querySelector(`#aspect-list-${component.excludedAspects[0].replace(':', '-')}`))
.toBeNull();
});
});
});
@ -256,7 +269,6 @@ describe('AspectListComponent', () => {
component = fixture.componentInstance;
aspectListService = TestBed.inject(AspectListService);
spyOn(aspectListService, 'getAspects').and.returnValue(of(aspectListMock));
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
@ -265,8 +277,17 @@ describe('AspectListComponent', () => {
});
it('should show all the aspects', async () => {
fixture.detectChanges();
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-FirstAspect' }))).toBe(true);
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-SecondAspect' }))).toBe(true);
});
it('should not show excluded aspects', async () => {
component.excludedAspects = ['frs:AspectOne', 'frs:SecondAspect'];
fixture.detectChanges();
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-FirstAspect' }))).toBeFalse();
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-SecondAspect' }))).toBeFalse();
});
});
});

View File

@ -35,6 +35,10 @@ export class AspectListComponent implements OnInit, OnDestroy {
@Input()
nodeId: string = '';
/** List of aspects' ids which should not be displayed. */
@Input()
excludedAspects?: string[] = [];
/** Emitted every time the user select a new aspect */
@Output()
valueChanged: EventEmitter<string[]> = new EventEmitter<string[]>();
@ -56,13 +60,14 @@ export class AspectListComponent implements OnInit, OnDestroy {
}
ngOnInit(): void {
let aspects$: Observable<AspectEntry[]>;
if (this.nodeId) {
const node$ = this.nodeApiService.getNode(this.nodeId);
const customAspect$ = this.aspectListService.getCustomAspects(this.aspectListService.getVisibleAspects())
.pipe(map(
(customAspects) => customAspects.flatMap((customAspect) => customAspect.entry.id)
));
this.aspects$ = zip(node$, customAspect$).pipe(
aspects$ = zip(node$, customAspect$).pipe(
tap(([node, customAspects]) => {
this.nodeAspects = node.aspectNames.filter((aspect) => this.aspectListService.getVisibleAspects().includes(aspect) || customAspects.includes(aspect));
this.nodeAspectStatus = [ ...this.nodeAspects ];
@ -71,9 +76,11 @@ export class AspectListComponent implements OnInit, OnDestroy {
concatMap(() => this.aspectListService.getAspects()),
takeUntil(this.onDestroy$));
} else {
this.aspects$ = this.aspectListService.getAspects()
aspects$ = this.aspectListService.getAspects()
.pipe(takeUntil(this.onDestroy$));
}
this.aspects$ = aspects$.pipe(map((aspects) =>
aspects.filter((aspect) => !this.excludedAspects.includes(aspect.entry.id))));
}
onCheckBoxClick(event: Event) {

View File

@ -17,10 +17,14 @@
import { TranslateModule } from '@ngx-translate/core';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { DialogAspectListService } from '@alfresco/adf-content-services';
import { DialogAspectListService } from './dialog-aspect-list.service';
import { AspectListDialogComponent } from '../aspect-list-dialog.component';
import { AspectListDialogComponentData } from '../aspect-list-dialog-data.interface';
import { CategoryService } from '../../category/services/category.service';
import { TagService } from '../../tag/services/tag.service';
import { TestBed } from '@angular/core/testing';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Subject } from 'rxjs';
import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
import { Observable, Subject } from 'rxjs';
describe('DialogAspectListService', () => {
let dialogAspectListService: DialogAspectListService;
@ -71,5 +75,67 @@ describe('DialogAspectListService', () => {
afterClosed$.next();
expect(document.querySelector).not.toHaveBeenCalled();
});
describe('Calling open on dialog', () => {
let expectedDialogConfig: MatDialogConfig<AspectListDialogComponentData>;
beforeEach(() => {
spyOn(dialog, 'open').and.returnValue({
afterClosed: () => new Observable<void>()
} as MatDialogRef<any>);
expectedDialogConfig = {
data: {
title: 'ADF-ASPECT-LIST.DIALOG.TITLE',
description: 'ADF-ASPECT-LIST.DIALOG.DESCRIPTION',
overTableMessage: 'ADF-ASPECT-LIST.DIALOG.OVER-TABLE-MESSAGE',
excludedAspects: [],
select: jasmine.any(Subject) as any,
nodeId: undefined
},
panelClass: 'adf-aspect-list-dialog',
width: '750px',
role: 'dialog',
disableClose: true
};
});
it('should call open on dialog with correct parameters when tagService.areTagsEnabled returns true', () => {
const tagService = TestBed.inject(TagService);
spyOn(tagService, 'areTagsEnabled').and.returnValue(true);
dialogAspectListService.openAspectListDialog();
expect(tagService.areTagsEnabled).toHaveBeenCalled();
expect(dialog.open).toHaveBeenCalledWith(AspectListDialogComponent, expectedDialogConfig);
});
it('should call open on dialog with correct parameters when tagService.areTagsEnabled returns false', () => {
const tagService = TestBed.inject(TagService);
spyOn(tagService, 'areTagsEnabled').and.returnValue(false);
expectedDialogConfig.data.excludedAspects = ['cm:taggable'];
dialogAspectListService.openAspectListDialog();
expect(tagService.areTagsEnabled).toHaveBeenCalled();
expect(dialog.open).toHaveBeenCalledWith(AspectListDialogComponent, expectedDialogConfig);
});
it('should call open on dialog with correct parameters when categoryService.areCategoriesEnabled returns true', () => {
const categoryService = TestBed.inject(CategoryService);
spyOn(categoryService, 'areCategoriesEnabled').and.returnValue(true);
dialogAspectListService.openAspectListDialog();
expect(categoryService.areCategoriesEnabled).toHaveBeenCalled();
expect(dialog.open).toHaveBeenCalledWith(AspectListDialogComponent, expectedDialogConfig);
});
it('should call open on dialog with correct parameters when categoryService.areCategoriesEnabled returns false', () => {
const categoryService = TestBed.inject(CategoryService);
spyOn(categoryService, 'areCategoriesEnabled').and.returnValue(false);
expectedDialogConfig.data.excludedAspects = ['cm:generalclassifiable'];
dialogAspectListService.openAspectListDialog();
expect(categoryService.areCategoriesEnabled).toHaveBeenCalled();
expect(dialog.open).toHaveBeenCalledWith(AspectListDialogComponent, expectedDialogConfig);
});
});
});
});

View File

@ -21,14 +21,20 @@ import { Observable, Subject } from 'rxjs';
import { AspectListDialogComponentData } from '../aspect-list-dialog-data.interface';
import { AspectListDialogComponent } from '../aspect-list-dialog.component';
import { OverlayContainer } from '@angular/cdk/overlay';
import { TagService } from '../../tag';
import { CategoryService } from '../../category';
@Injectable({
providedIn: 'root'
})
export class DialogAspectListService {
constructor(private dialog: MatDialog, private overlayContainer: OverlayContainer) {
}
constructor(
private dialog: MatDialog,
private overlayContainer: OverlayContainer,
private tagService: TagService,
private categoryService: CategoryService
) {}
openAspectListDialog(nodeId?: string, selectorAutoFocusedOnClose?: string): Observable<string[]> {
const select = new Subject<string[]>();
@ -41,7 +47,11 @@ export class DialogAspectListService {
description: 'ADF-ASPECT-LIST.DIALOG.DESCRIPTION',
overTableMessage: 'ADF-ASPECT-LIST.DIALOG.OVER-TABLE-MESSAGE',
select,
nodeId
nodeId,
excludedAspects: [
...this.tagService.areTagsEnabled() ? [] : ['cm:taggable'],
...this.categoryService.areCategoriesEnabled() ? [] : ['cm:generalclassifiable']
]
};
this.openDialog(data, 'adf-aspect-list-dialog', '750px', selectorAutoFocusedOnClose);

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { CoreTestingModule, UserPreferencesService } from '@alfresco/adf-core';
import { AppConfigService, CoreTestingModule, UserPreferencesService } from '@alfresco/adf-core';
import {
CategoryBody,
CategoryEntry,
@ -177,4 +177,27 @@ describe('CategoryService', () => {
expect(linkCategoriesSpy).toHaveBeenCalledOnceWith(fakeNodeId, fakeCategoriesLinkBodies);
});
}));
describe('areCategoriesEnabled', () => {
let getSpy: jasmine.Spy<(key: string, defaultValue?: boolean) => boolean>;
beforeEach(() => {
getSpy = spyOn(TestBed.inject(AppConfigService), 'get');
});
it('should call get on AppConfigService with correct parameters', () => {
categoryService.areCategoriesEnabled();
expect(getSpy).toHaveBeenCalledWith('plugins.categories', true);
});
it('should return true if get from AppConfigService returns true', () => {
getSpy.and.returnValue(true);
expect(categoryService.areCategoriesEnabled()).toBeTrue();
});
it('should return false if get from AppConfigService returns false', () => {
getSpy.and.returnValue(false);
expect(categoryService.areCategoriesEnabled()).toBeFalse();
});
});
});

View File

@ -16,7 +16,7 @@
*/
import { Injectable } from '@angular/core';
import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
import { AlfrescoApiService, AppConfigService, UserPreferencesService } from '@alfresco/adf-core';
import { CategoriesApi, CategoryBody, CategoryEntry, CategoryLinkBody, CategoryPaging, ResultSetPaging, SearchApi } from '@alfresco/js-api';
import { from, Observable } from 'rxjs';
@ -35,7 +35,11 @@ export class CategoryService {
return this._searchApi;
}
constructor(private apiService: AlfrescoApiService, private userPreferencesService: UserPreferencesService) {}
constructor(
private apiService: AlfrescoApiService,
private userPreferencesService: UserPreferencesService,
private appConfigService: AppConfigService
) {}
/**
* Get subcategories of a given parent category
@ -152,4 +156,13 @@ export class CategoryService {
linkNodeToCategory(nodeId: string, categoryLinkBodyCreate: CategoryLinkBody[]): Observable<CategoryPaging | CategoryEntry> {
return from(this.categoriesApi.linkNodeToCategory(nodeId, categoryLinkBodyCreate));
}
/**
* Checks if categories plugin is enabled.
*
* @returns boolean true if categories plugin is enabled, false otherwise.
*/
areCategoriesEnabled(): boolean {
return this.appConfigService.get('plugins.categories', true);
}
}

View File

@ -27,4 +27,7 @@ export interface SearchCategory {
selector: string;
settings: SearchWidgetSettings;
};
rules?: {
visible: string;
};
}

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { UserPreferencesService } from '@alfresco/adf-core';
import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core';
import { TagService } from './tag.service';
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { ContentTestingModule } from '../../testing/content.testing.module';
@ -339,5 +339,28 @@ describe('TagService', () => {
tick();
}));
});
describe('areTagsEnabled', () => {
let getSpy: jasmine.Spy<(key: string, defaultValue?: boolean) => boolean>;
beforeEach(() => {
getSpy = spyOn(TestBed.inject(AppConfigService), 'get');
});
it('should call get on AppConfigService with correct parameters', () => {
service.areTagsEnabled();
expect(getSpy).toHaveBeenCalledWith('plugins.tags', true);
});
it('should return true if get from AppConfigService returns true', () => {
getSpy.and.returnValue(true);
expect(service.areTagsEnabled()).toBeTrue();
});
it('should return false if get from AppConfigService returns false', () => {
getSpy.and.returnValue(false);
expect(service.areTagsEnabled()).toBeFalse();
});
});
});
});

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
import { AlfrescoApiService, AppConfigService, UserPreferencesService } from '@alfresco/adf-core';
import { EventEmitter, Injectable, Output } from '@angular/core';
import { from, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
@ -35,7 +35,11 @@ export class TagService {
@Output()
refresh = new EventEmitter();
constructor(private apiService: AlfrescoApiService, private userPreferencesService: UserPreferencesService) {}
constructor(
private apiService: AlfrescoApiService,
private userPreferencesService: UserPreferencesService,
private appConfigService: AppConfigService
) {}
/**
* Gets a list of tags added to a node.
@ -172,4 +176,13 @@ export class TagService {
assignTagsToNode(nodeId: string, tags: TagBody[]): Observable<TagPaging | TagEntry> {
return from(this.tagsApi.assignTagsToNode(nodeId, tags)).pipe(tap((data) => this.refresh.emit(data)));
}
/**
* Checks if tags plugin is enabled.
*
* @returns boolean true if tags plugin is enabled, false otherwise.
*/
areTagsEnabled(): boolean {
return this.appConfigService.get('plugins.tags', true);
}
}