mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
ACS-8772: Migrate node tooltip to Angular signals (#11498)
This commit is contained in:
@@ -33,10 +33,10 @@ import { IconModule } from '@alfresco/adf-core';
|
||||
})
|
||||
export class DropdownBreadcrumbComponent extends BreadcrumbComponent implements OnChanges {
|
||||
@ViewChild('dropdown')
|
||||
dropdown: MatSelect;
|
||||
declare dropdown: MatSelect;
|
||||
|
||||
currentNode: PathElement;
|
||||
previousNodes: PathElement[];
|
||||
declare previousNodes: PathElement[];
|
||||
|
||||
/**
|
||||
* Calculate the current and previous nodes from the route array
|
||||
|
||||
@@ -32,7 +32,6 @@ import { CONTENT_PERMISSION_MANAGER_DIRECTIVES } from './permission-manager/perm
|
||||
import { ASPECT_LIST_DIRECTIVES } from './aspect-list/aspect-list.module';
|
||||
import { versionCompatibilityFactory } from './version-compatibility/version-compatibility-factory';
|
||||
import { VersionCompatibilityService } from './version-compatibility/version-compatibility.service';
|
||||
import { CONTENT_PIPES } from './pipes/content-pipe.module';
|
||||
import { contentAuthLoaderFactory } from './auth-loader/content-auth-loader-factory';
|
||||
import { ContentAuthLoaderService } from './auth-loader/content-auth-loader.service';
|
||||
import { CategoriesManagementComponent } from './category';
|
||||
@@ -55,7 +54,6 @@ import { AlfrescoApiLoaderService, createAlfrescoApiInstance } from './api-facto
|
||||
MaterialModule,
|
||||
MatDatetimepickerModule,
|
||||
MatNativeDatetimeModule,
|
||||
...CONTENT_PIPES,
|
||||
...CONTENT_TAG_DIRECTIVES,
|
||||
...CONTENT_DIALOG_DIRECTIVES,
|
||||
...CONTENT_SEARCH_DIRECTIVES,
|
||||
@@ -82,7 +80,6 @@ import { AlfrescoApiLoaderService, createAlfrescoApiInstance } from './api-facto
|
||||
providers: [provideTranslations('adf-content-services', 'assets/adf-content-services')],
|
||||
exports: [
|
||||
MaterialModule,
|
||||
...CONTENT_PIPES,
|
||||
...CONTENT_TAG_DIRECTIVES,
|
||||
...DOCUMENT_LIST_DIRECTIVES,
|
||||
...CONTENT_UPLOAD_DIRECTIVES,
|
||||
|
||||
@@ -125,7 +125,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
|
||||
DEFAULT_SORTING: DataSorting[] = [new DataSorting('name', 'asc'), new DataSorting('isFolder', 'desc')];
|
||||
|
||||
@ContentChild(DataColumnListComponent)
|
||||
columnList: DataColumnListComponent;
|
||||
declare columnList: DataColumnListComponent;
|
||||
|
||||
@ContentChild(CustomLoadingContentTemplateDirective)
|
||||
customLoadingContent: CustomLoadingContentTemplateDirective;
|
||||
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { LibraryNameColumnComponent } from './library-name-column.component';
|
||||
|
||||
describe('LibraryNameColumnComponent', () => {
|
||||
let fixture: ComponentFixture<LibraryNameColumnComponent>;
|
||||
let component: LibraryNameColumnComponent;
|
||||
let node;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [LibraryNameColumnComponent]
|
||||
});
|
||||
node = {
|
||||
id: 'nodeId',
|
||||
path: {
|
||||
elements: []
|
||||
}
|
||||
};
|
||||
fixture = TestBed.createComponent(LibraryNameColumnComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
describe('makeLibraryTooltip()', () => {
|
||||
it('maps tooltip to description', () => {
|
||||
node.description = 'description';
|
||||
const tooltip = component.makeLibraryTooltip(node);
|
||||
|
||||
expect(tooltip).toBe(node.description);
|
||||
});
|
||||
|
||||
it('maps tooltip to description', () => {
|
||||
node.title = 'title';
|
||||
const tooltip = component.makeLibraryTooltip(node);
|
||||
|
||||
expect(tooltip).toBe(node.title);
|
||||
});
|
||||
|
||||
it('sets tooltip to empty string', () => {
|
||||
const tooltip = component.makeLibraryTooltip(node);
|
||||
|
||||
expect(tooltip).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('makeLibraryTitle()', () => {
|
||||
it('sets title with id when duplicate nodes title exists in list', () => {
|
||||
node.title = 'title';
|
||||
|
||||
const rows = [{ node: { entry: { id: 'some-id', title: 'title' } } }] as any[];
|
||||
|
||||
const title = component.makeLibraryTitle(node, rows);
|
||||
expect(title).toContain('nodeId');
|
||||
});
|
||||
|
||||
it('sets title when no duplicate nodes title exists in list', () => {
|
||||
node.title = 'title';
|
||||
|
||||
const rows = [
|
||||
{
|
||||
node: { entry: { id: 'some-id', title: 'title-some-id' } }
|
||||
}
|
||||
] as any[];
|
||||
|
||||
const title = component.makeLibraryTitle(node, rows);
|
||||
|
||||
expect(title).toBe('title');
|
||||
});
|
||||
});
|
||||
});
|
||||
+9
-23
@@ -16,13 +16,14 @@
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { NodeEntry, Site } from '@alfresco/js-api';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-library-name-column',
|
||||
@@ -62,7 +63,10 @@ export class LibraryNameColumnComponent implements OnInit {
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(private element: ElementRef, private nodesApiService: NodesApiService) {}
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
private nodesApiService: NodesApiService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.updateValue();
|
||||
@@ -84,8 +88,9 @@ export class LibraryNameColumnComponent implements OnInit {
|
||||
this.node = this.context.row.node;
|
||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||
if (this.node?.entry) {
|
||||
this.displayText$.next(this.makeLibraryTitle(this.node.entry as any, rows));
|
||||
this.displayTooltip$.next(this.makeLibraryTooltip(this.node.entry));
|
||||
const allEntries = rows.map((row: ShareDataRow) => row.node.entry);
|
||||
this.displayText$.next(NodeTooltipUtils.getLibraryTitle(this.node.entry, allEntries));
|
||||
this.displayTooltip$.next(NodeTooltipUtils.getLibraryTooltip(this.node));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,23 +104,4 @@ export class LibraryNameColumnComponent implements OnInit {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
makeLibraryTooltip(library: any): string {
|
||||
const { description, title } = library;
|
||||
|
||||
return description || title || '';
|
||||
}
|
||||
|
||||
makeLibraryTitle(library: Site, rows: Array<ShareDataRow>): string {
|
||||
const entries = rows.map((row: ShareDataRow) => row.node.entry);
|
||||
const { title, id } = library;
|
||||
|
||||
let isDuplicate = false;
|
||||
|
||||
if (entries) {
|
||||
isDuplicate = entries.some((entry: any) => entry.id !== id && entry.title === title);
|
||||
}
|
||||
|
||||
return isDuplicate ? `${title} (${id})` : `${title}`;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-24
@@ -35,11 +35,10 @@ describe('LibraryRoleColumnComponent', () => {
|
||||
row: { node: { entry: { role: 'SiteManager' } } }
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.MANAGER');
|
||||
|
||||
expect(component.displayText()).toBe('LIBRARY.ROLE.MANAGER');
|
||||
});
|
||||
|
||||
it('should render Collaborator', () => {
|
||||
@@ -47,11 +46,10 @@ describe('LibraryRoleColumnComponent', () => {
|
||||
row: { node: { entry: { role: 'SiteCollaborator' } } }
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.COLLABORATOR');
|
||||
|
||||
expect(component.displayText()).toBe('LIBRARY.ROLE.COLLABORATOR');
|
||||
});
|
||||
|
||||
it('should render Contributor', () => {
|
||||
@@ -59,11 +57,10 @@ describe('LibraryRoleColumnComponent', () => {
|
||||
row: { node: { entry: { role: 'SiteContributor' } } }
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.CONTRIBUTOR');
|
||||
|
||||
expect(component.displayText()).toBe('LIBRARY.ROLE.CONTRIBUTOR');
|
||||
});
|
||||
|
||||
it('should render Consumer', () => {
|
||||
@@ -71,11 +68,10 @@ describe('LibraryRoleColumnComponent', () => {
|
||||
row: { node: { entry: { role: 'SiteConsumer' } } }
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.CONSUMER');
|
||||
|
||||
expect(component.displayText()).toBe('LIBRARY.ROLE.CONSUMER');
|
||||
});
|
||||
|
||||
it('should not render text for unknown', () => {
|
||||
@@ -83,11 +79,10 @@ describe('LibraryRoleColumnComponent', () => {
|
||||
row: { node: { entry: { role: 'ROLE' } } }
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.NONE');
|
||||
|
||||
expect(component.displayText()).toBe('LIBRARY.ROLE.NONE');
|
||||
});
|
||||
|
||||
it('should take role from obj when node entry role is not provided', () => {
|
||||
@@ -98,10 +93,9 @@ describe('LibraryRoleColumnComponent', () => {
|
||||
}
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.MANAGER');
|
||||
|
||||
expect(component.displayText()).toBe('LIBRARY.ROLE.MANAGER');
|
||||
});
|
||||
});
|
||||
|
||||
+23
-25
@@ -15,21 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, DestroyRef, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ChangeDetectionStrategy, Component, computed, DestroyRef, inject, Input, OnInit, signal, ViewEncapsulation } from '@angular/core';
|
||||
import { Site } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-library-role-column',
|
||||
imports: [AsyncPipe, TranslatePipe],
|
||||
imports: [TranslatePipe],
|
||||
template: `
|
||||
<span class="adf-datatable-cell-value" title="{{ displayText$ | async | translate }}">
|
||||
{{ displayText$ | async | translate }}
|
||||
<span class="adf-datatable-cell-value" [title]="displayText() | translate">
|
||||
{{ displayText() | translate }}
|
||||
</span>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
@@ -40,7 +38,23 @@ export class LibraryRoleColumnComponent implements OnInit {
|
||||
@Input({ required: true })
|
||||
context: any;
|
||||
|
||||
displayText$ = new BehaviorSubject<string>('');
|
||||
private readonly role = signal<string | undefined>(undefined);
|
||||
|
||||
readonly displayText = computed(() => {
|
||||
const roleValue = this.role();
|
||||
switch (roleValue) {
|
||||
case Site.RoleEnum.SiteManager:
|
||||
return 'LIBRARY.ROLE.MANAGER';
|
||||
case Site.RoleEnum.SiteCollaborator:
|
||||
return 'LIBRARY.ROLE.COLLABORATOR';
|
||||
case Site.RoleEnum.SiteContributor:
|
||||
return 'LIBRARY.ROLE.CONTRIBUTOR';
|
||||
case Site.RoleEnum.SiteConsumer:
|
||||
return 'LIBRARY.ROLE.CONSUMER';
|
||||
default:
|
||||
return 'LIBRARY.ROLE.NONE';
|
||||
}
|
||||
});
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
@@ -63,23 +77,7 @@ export class LibraryRoleColumnComponent implements OnInit {
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
const role = this.context.row.node?.entry.role ?? this.context.row.obj.role;
|
||||
switch (role) {
|
||||
case Site.RoleEnum.SiteManager:
|
||||
this.displayText$.next('LIBRARY.ROLE.MANAGER');
|
||||
break;
|
||||
case Site.RoleEnum.SiteCollaborator:
|
||||
this.displayText$.next('LIBRARY.ROLE.COLLABORATOR');
|
||||
break;
|
||||
case Site.RoleEnum.SiteContributor:
|
||||
this.displayText$.next('LIBRARY.ROLE.CONTRIBUTOR');
|
||||
break;
|
||||
case Site.RoleEnum.SiteConsumer:
|
||||
this.displayText$.next('LIBRARY.ROLE.CONSUMER');
|
||||
break;
|
||||
default:
|
||||
this.displayText$.next('LIBRARY.ROLE.NONE');
|
||||
break;
|
||||
}
|
||||
const roleValue = this.context.row.node?.entry.role ?? this.context.row.obj.role;
|
||||
this.role.set(roleValue);
|
||||
}
|
||||
}
|
||||
|
||||
+153
-11
@@ -18,8 +18,13 @@
|
||||
import { NameColumnComponent } from './name-column.component';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { skip } from 'rxjs/operators';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
|
||||
describe('NameColumnComponent', () => {
|
||||
const nodeName = 'node-name';
|
||||
const nodeTitle = 'node-title';
|
||||
const nodeDescription = 'node-description';
|
||||
|
||||
let fixture: ComponentFixture<NameColumnComponent>;
|
||||
let context: any;
|
||||
let component: NameColumnComponent;
|
||||
@@ -42,22 +47,159 @@ describe('NameColumnComponent', () => {
|
||||
component.context = context;
|
||||
});
|
||||
|
||||
it('should set the display value based on default key', (done) => {
|
||||
component.displayText$.pipe(skip(1)).subscribe((value) => {
|
||||
expect(value).toBe('name');
|
||||
done();
|
||||
describe('Display Text', () => {
|
||||
it('should set the display value based on default key', (done) => {
|
||||
component.displayText$.pipe(skip(1)).subscribe((value) => {
|
||||
expect(value).toBe('name');
|
||||
done();
|
||||
});
|
||||
|
||||
component.ngOnInit();
|
||||
});
|
||||
|
||||
component.ngOnInit();
|
||||
it('should set the display value based on the custom key', (done) => {
|
||||
component.key = 'title';
|
||||
component.displayText$.pipe(skip(1)).subscribe((value) => {
|
||||
expect(value).toBe('title');
|
||||
done();
|
||||
});
|
||||
|
||||
component.ngOnInit();
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the display value based on the custom key', (done) => {
|
||||
component.key = 'title';
|
||||
component.displayText$.pipe(skip(1)).subscribe((value) => {
|
||||
expect(value).toBe('title');
|
||||
done();
|
||||
describe('Tooltip Logic', () => {
|
||||
it('should return null when missing node', () => {
|
||||
component.context.row.node = null;
|
||||
component.ngOnInit();
|
||||
expect(component.tooltip()).toBe(null);
|
||||
});
|
||||
|
||||
component.ngOnInit();
|
||||
it('should return null when missing node entry', () => {
|
||||
component.context.row.node = {} as any;
|
||||
component.ngOnInit();
|
||||
expect(component.tooltip()).toBe(null);
|
||||
});
|
||||
|
||||
it('should use title and description when all fields present', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeTitle,
|
||||
'cm:description': nodeDescription
|
||||
}
|
||||
}
|
||||
};
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(`${nodeTitle}\n${nodeDescription}`);
|
||||
});
|
||||
|
||||
it('should use name when other properties are missing', () => {
|
||||
const node = {
|
||||
entry: {
|
||||
name: nodeName
|
||||
}
|
||||
} as NodeEntry;
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should display name when title and description are missing', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {}
|
||||
}
|
||||
};
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should use name and description when title is missing', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': null,
|
||||
'cm:description': nodeDescription
|
||||
}
|
||||
}
|
||||
};
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(`${nodeName}\n${nodeDescription}`);
|
||||
});
|
||||
|
||||
it('should use name and title when description is missing', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeTitle,
|
||||
'cm:description': null
|
||||
}
|
||||
}
|
||||
};
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(`${nodeName}\n${nodeTitle}`);
|
||||
});
|
||||
|
||||
it('should use name if name and description are the same', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': null,
|
||||
'cm:description': nodeName
|
||||
}
|
||||
}
|
||||
};
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should use name if name and title are the same', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeName,
|
||||
'cm:description': null
|
||||
}
|
||||
}
|
||||
};
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should use name if all values are the same', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeName,
|
||||
'cm:description': nodeName
|
||||
}
|
||||
}
|
||||
};
|
||||
component.context.row.node = node;
|
||||
component.ngOnInit();
|
||||
const tooltip = component.tooltip();
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+13
-7
@@ -15,19 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, computed, DestroyRef, ElementRef, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { NodeNameTooltipPipe } from '../../../pipes/node-name-tooltip.pipe';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-name-column',
|
||||
imports: [AsyncPipe, TranslatePipe, NodeNameTooltipPipe],
|
||||
imports: [AsyncPipe, TranslatePipe],
|
||||
template: `
|
||||
<span
|
||||
role="link"
|
||||
@@ -39,7 +39,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
}
|
||||
"
|
||||
class="adf-datatable-cell-value"
|
||||
title="{{ node | adfNodeNameTooltip }}"
|
||||
[title]="tooltip()"
|
||||
(click)="onClick()"
|
||||
tabindex="0"
|
||||
(keyup.enter)="onClick()"
|
||||
@@ -53,6 +53,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
})
|
||||
export class NameColumnComponent implements OnInit {
|
||||
@Input({ required: true })
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
context: any;
|
||||
|
||||
@Input()
|
||||
@@ -61,9 +62,14 @@ export class NameColumnComponent implements OnInit {
|
||||
displayText$ = new BehaviorSubject<string>('');
|
||||
node: NodeEntry;
|
||||
|
||||
readonly tooltip = computed(() => NodeTooltipUtils.getNodeTooltip(this.node));
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(private element: ElementRef, private nodesApiService: NodesApiService) {}
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
private nodesApiService: NodesApiService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.updateValue();
|
||||
@@ -85,8 +91,8 @@ export class NameColumnComponent implements OnInit {
|
||||
this.node = this.context.row.node;
|
||||
|
||||
if (this.node?.entry) {
|
||||
const displayText = this.context.row.getValue(this.key);
|
||||
this.displayText$.next(displayText || this.node.entry.id);
|
||||
const displayValue = this.context.row.getValue(this.key);
|
||||
this.displayText$.next(displayValue || this.node.entry.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-31
@@ -15,36 +15,29 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, computed, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NodeNameTooltipPipe } from '../../../pipes/node-name-tooltip.pipe';
|
||||
import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-trashcan-name-column',
|
||||
imports: [CommonModule, NodeNameTooltipPipe],
|
||||
template: `
|
||||
<ng-container *ngIf="!isLibrary">
|
||||
<span class="adf-datatable-cell-value" title="{{ node | adfNodeNameTooltip }}">{{ displayText }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="isLibrary">
|
||||
<span class="adf-datatable-cell-value" title="{{ displayTooltip }}">{{ displayText }}</span>
|
||||
</ng-container>
|
||||
`,
|
||||
template: `<span class="adf-datatable-cell-value" [title]="tooltip()">{{ displayText }}</span>`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'adf-datatable-content-cell adf-trashcan-name-column' }
|
||||
})
|
||||
export class TrashcanNameColumnComponent implements OnInit {
|
||||
@Input({ required: true })
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
context: any;
|
||||
|
||||
isLibrary = false;
|
||||
displayText: string;
|
||||
displayTooltip: string;
|
||||
node: NodeEntry;
|
||||
|
||||
readonly tooltip = computed(() => (this.isLibrary ? NodeTooltipUtils.getLibraryTooltip(this.node) : NodeTooltipUtils.getNodeTooltip(this.node)));
|
||||
|
||||
ngOnInit() {
|
||||
this.node = this.context.row.node;
|
||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||
@@ -53,27 +46,11 @@ export class TrashcanNameColumnComponent implements OnInit {
|
||||
this.isLibrary = this.node.entry.nodeType === 'st:site';
|
||||
|
||||
if (this.isLibrary) {
|
||||
const { properties } = this.node.entry;
|
||||
|
||||
this.displayText = this.makeLibraryTitle(this.node.entry, rows);
|
||||
this.displayTooltip = properties['cm:description'] || properties['cm:title'];
|
||||
const allEntries = rows.map((row) => row.node.entry);
|
||||
this.displayText = NodeTooltipUtils.getLibraryTitle(this.node.entry, allEntries);
|
||||
} else {
|
||||
this.displayText = this.node.entry.name || this.node.entry.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
makeLibraryTitle(library: any, rows: Array<ShareDataRow>): string {
|
||||
const entries = rows.map((r: ShareDataRow) => r.node.entry);
|
||||
const { id } = library;
|
||||
const title = library.properties['cm:title'];
|
||||
|
||||
let isDuplicate = false;
|
||||
|
||||
if (entries) {
|
||||
isDuplicate = entries.some((entry: any) => entry.id !== id && entry.properties['cm:title'] === title);
|
||||
}
|
||||
|
||||
return isDuplicate ? `${library.properties['cm:title']} (${library.name})` : `${library.properties['cm:title']}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,4 +49,7 @@ export * from './models/node-action.enum';
|
||||
|
||||
export * from './interfaces/document-list-loader.interface';
|
||||
|
||||
// utils
|
||||
export * from './utils/node-tooltip.utils';
|
||||
|
||||
export * from './document-list.module';
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 { NodeEntry } from '@alfresco/js-api';
|
||||
import { NodeTooltipUtils } from './node-tooltip.utils';
|
||||
|
||||
describe('NodeTooltipUtils', () => {
|
||||
const nodeName = 'node-name';
|
||||
const nodeTitle = 'node-title';
|
||||
const nodeDescription = 'node-description';
|
||||
|
||||
describe('getNodeTooltip', () => {
|
||||
it('should return null when node is null', () => {
|
||||
const result = NodeTooltipUtils.getNodeTooltip(null as any);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
it('should return null when node entry is missing', () => {
|
||||
const node = {} as NodeEntry;
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
it('should return name only when title and description are missing', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
expect(result).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should return name only when properties object is empty', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
expect(result).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should return title and description when both are present', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeTitle,
|
||||
'cm:description': nodeDescription
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
expect(result).toBe(`${nodeTitle}\n${nodeDescription}`);
|
||||
});
|
||||
|
||||
it('should return name and title when only title is present', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeTitle
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
expect(result).toBe(`${nodeName}\n${nodeTitle}`);
|
||||
});
|
||||
|
||||
it('should return name and description when only description is present', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:description': nodeDescription
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
expect(result).toBe(`${nodeName}\n${nodeDescription}`);
|
||||
});
|
||||
|
||||
it('should remove case-insensitive duplicates', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: 'Same-Name',
|
||||
properties: {
|
||||
'cm:title': 'same-name'
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
expect(result).toBe('Same-Name');
|
||||
});
|
||||
|
||||
it('should preserve order when removing duplicates', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: 'First',
|
||||
properties: {
|
||||
'cm:title': 'Second',
|
||||
'cm:description': 'FIRST'
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getNodeTooltip(node);
|
||||
// When both title and description exist, shows "title\ndescription"
|
||||
// 'FIRST' is a case-insensitive duplicate of 'First', but since we're using title+description logic,
|
||||
// the duplicate check happens between 'Second' and 'FIRST', so 'FIRST' remains
|
||||
expect(result).toBe('Second\nFIRST');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLibraryTooltip', () => {
|
||||
it('should return empty string when node is null', () => {
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(null as any);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return empty string when node entry is missing', () => {
|
||||
const node = {} as NodeEntry;
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(node);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return description when available', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
properties: {
|
||||
'cm:title': 'Library Title',
|
||||
'cm:description': 'Library Description'
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(node);
|
||||
expect(result).toBe('Library Description');
|
||||
});
|
||||
|
||||
it('should return title when description is not available', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
properties: {
|
||||
'cm:title': 'Library Title'
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(node);
|
||||
expect(result).toBe('Library Title');
|
||||
});
|
||||
|
||||
it('should return empty string when neither description nor title are available', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
properties: {}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(node);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should handle direct properties (description and title)', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
description: 'Direct Description',
|
||||
title: 'Direct Title'
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(node);
|
||||
expect(result).toBe('Direct Description');
|
||||
});
|
||||
|
||||
it('should prefer direct description over cm:description', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
description: 'Direct Description',
|
||||
properties: {
|
||||
'cm:description': 'CM Description'
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(node);
|
||||
expect(result).toBe('Direct Description');
|
||||
});
|
||||
|
||||
it('should fall back to cm:description when direct description is not available', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
properties: {
|
||||
'cm:description': 'CM Description'
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = NodeTooltipUtils.getLibraryTooltip(node);
|
||||
expect(result).toBe('CM Description');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLibraryTitle', () => {
|
||||
it('should return empty string when library is null', () => {
|
||||
const result = NodeTooltipUtils.getLibraryTitle(null, []);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should return title when no duplicates exist', () => {
|
||||
const library = { id: 'lib1', title: 'Library Title' };
|
||||
const allEntries = [
|
||||
{ id: 'lib2', title: 'Other Title' },
|
||||
{ id: 'lib3', title: 'Another Title' }
|
||||
];
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, allEntries);
|
||||
expect(result).toBe('Library Title');
|
||||
});
|
||||
|
||||
it('should append ID when duplicate title exists', () => {
|
||||
const library = { id: 'lib1', title: 'Duplicate Title' };
|
||||
const allEntries = [
|
||||
{ id: 'lib2', title: 'Duplicate Title' },
|
||||
{ id: 'lib3', title: 'Other Title' }
|
||||
];
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, allEntries);
|
||||
expect(result).toBe('Duplicate Title (lib1)');
|
||||
});
|
||||
|
||||
it('should append name when duplicate title exists and name is available', () => {
|
||||
const library = { id: 'lib1', name: 'library-name', title: 'Duplicate Title' };
|
||||
const allEntries = [{ id: 'lib2', title: 'Duplicate Title' }];
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, allEntries);
|
||||
expect(result).toBe('Duplicate Title (library-name)');
|
||||
});
|
||||
|
||||
it('should handle cm:title properties', () => {
|
||||
const library = {
|
||||
id: 'lib1',
|
||||
name: 'library-name',
|
||||
properties: { 'cm:title': 'CM Title' }
|
||||
};
|
||||
const allEntries = [{ id: 'lib2', properties: { 'cm:title': 'CM Title' } }];
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, allEntries);
|
||||
expect(result).toBe('CM Title (library-name)');
|
||||
});
|
||||
|
||||
it('should not append suffix when no duplicate exists', () => {
|
||||
const library = { id: 'lib1', name: 'library-name', title: 'Unique Title' };
|
||||
const allEntries = [{ id: 'lib2', title: 'Other Title' }];
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, allEntries);
|
||||
expect(result).toBe('Unique Title');
|
||||
});
|
||||
|
||||
it('should return name when title is missing', () => {
|
||||
const library = { id: 'lib1', name: 'library-name' };
|
||||
const allEntries = [];
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, allEntries);
|
||||
// Returns name when available, otherwise id
|
||||
expect(result).toBe('library-name');
|
||||
});
|
||||
|
||||
it('should handle empty entries array', () => {
|
||||
const library = { id: 'lib1', title: 'Library Title' };
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, []);
|
||||
expect(result).toBe('Library Title');
|
||||
});
|
||||
|
||||
it('should not consider same library as duplicate', () => {
|
||||
const library = { id: 'lib1', title: 'Library Title' };
|
||||
const allEntries = [
|
||||
{ id: 'lib1', title: 'Library Title' },
|
||||
{ id: 'lib2', title: 'Other Title' }
|
||||
];
|
||||
const result = NodeTooltipUtils.getLibraryTitle(library, allEntries);
|
||||
expect(result).toBe('Library Title');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,144 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 { NodeEntry } from '@alfresco/js-api';
|
||||
|
||||
/**
|
||||
* Utility class for generating node and library tooltips based on node properties
|
||||
*/
|
||||
export class NodeTooltipUtils {
|
||||
/**
|
||||
* Generates a tooltip string for a node based on its name, title, and description properties.
|
||||
* The tooltip logic follows these rules:
|
||||
* - If both title and description exist: shows "title\ndescription"
|
||||
* - If only title exists: shows "name\ntitle"
|
||||
* - If only description exists: shows "name\ndescription"
|
||||
* - If neither exists: shows "name"
|
||||
* - Removes case-insensitive duplicates while preserving order
|
||||
*
|
||||
* @param node - The node entry to generate tooltip for
|
||||
* @returns The tooltip string with newline-separated lines, or null if node is invalid
|
||||
*/
|
||||
static getNodeTooltip(node: NodeEntry): string | null {
|
||||
if (!node?.entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
entry: { properties, name }
|
||||
} = node;
|
||||
|
||||
const title = properties?.['cm:title'];
|
||||
const description = properties?.['cm:description'];
|
||||
|
||||
// Build lines array based on available properties
|
||||
const lines: string[] = [];
|
||||
|
||||
// Determine first line: title if available and different from name, otherwise name
|
||||
if (title && description) {
|
||||
lines.push(title, description);
|
||||
} else if (title) {
|
||||
lines.push(name, title);
|
||||
} else if (description) {
|
||||
lines.push(name, description);
|
||||
} else {
|
||||
lines.push(name);
|
||||
}
|
||||
|
||||
// Remove case-insensitive duplicates while preserving order
|
||||
return this.removeDuplicates(lines).join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a tooltip string for a library (site) node.
|
||||
* Returns description if available, otherwise title, otherwise empty string.
|
||||
*
|
||||
* @param node - The node entry to generate tooltip for
|
||||
* @returns The tooltip string, or empty string if no description or title is available
|
||||
*/
|
||||
static getLibraryTooltip(node: NodeEntry): string {
|
||||
if (!node?.entry) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const { properties, description, title } = node.entry as any;
|
||||
|
||||
// Check both direct properties and cm: properties for compatibility
|
||||
const desc = description || properties?.['cm:description'];
|
||||
const ttl = title || properties?.['cm:title'];
|
||||
|
||||
return desc || ttl || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a display title for a library (site) node.
|
||||
* If there are duplicate titles in the list, appends the library ID/name in parentheses.
|
||||
*
|
||||
* @param library - The library entry object
|
||||
* @param allEntries - Array of all entries to check for duplicates
|
||||
* @returns The display title, with ID/name appended if duplicate exists
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
static getLibraryTitle(library: any, allEntries: any[]): string {
|
||||
if (!library) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Support both direct properties and cm: properties
|
||||
const libraryId = library.id;
|
||||
const libraryName = library.name;
|
||||
const libraryTitle = library.title || library.properties?.['cm:title'];
|
||||
|
||||
if (!libraryTitle) {
|
||||
return libraryName || libraryId || '';
|
||||
}
|
||||
|
||||
// Check if there are duplicate titles in the list
|
||||
let isDuplicate = false;
|
||||
|
||||
if (allEntries && allEntries.length > 0) {
|
||||
isDuplicate = allEntries.some((entry) => {
|
||||
const entryId = entry.id;
|
||||
const entryTitle = entry.title || entry.properties?.['cm:title'];
|
||||
return entryId !== libraryId && entryTitle === libraryTitle;
|
||||
});
|
||||
}
|
||||
|
||||
// If duplicate, append the ID or name in parentheses
|
||||
const suffix = libraryName || libraryId;
|
||||
return isDuplicate && suffix ? `${libraryTitle} (${suffix})` : libraryTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes case-insensitive duplicate strings from an array while preserving order
|
||||
*
|
||||
* @param lines - Array of strings to deduplicate
|
||||
* @returns Array with duplicates removed
|
||||
*/
|
||||
private static removeDuplicates(lines: string[]): string[] {
|
||||
const seen = new Set<string>();
|
||||
return lines.filter((line) => {
|
||||
const lowerLine = line.toLowerCase();
|
||||
if (seen.has(lowerLine)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(lowerLine);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 { NgModule } from '@angular/core';
|
||||
import { NodeNameTooltipPipe } from './node-name-tooltip.pipe';
|
||||
|
||||
export const CONTENT_PIPES = [NodeNameTooltipPipe] as const;
|
||||
|
||||
/**
|
||||
* @deprecated Use the individual pipe modules instead.
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [...CONTENT_PIPES],
|
||||
providers: [...CONTENT_PIPES],
|
||||
exports: [...CONTENT_PIPES]
|
||||
})
|
||||
export class ContentPipeModule {}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './public-api';
|
||||
@@ -1,144 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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 { NodeEntry } from '@alfresco/js-api';
|
||||
import { NodeNameTooltipPipe } from './node-name-tooltip.pipe';
|
||||
|
||||
describe('NodeNameTooltipPipe', () => {
|
||||
const nodeName = 'node-name';
|
||||
const nodeTitle = 'node-title';
|
||||
const nodeDescription = 'node-description';
|
||||
|
||||
let pipe: NodeNameTooltipPipe;
|
||||
|
||||
beforeEach(() => {
|
||||
pipe = new NodeNameTooltipPipe();
|
||||
});
|
||||
|
||||
it('should not transform when missing node', () => {
|
||||
expect(pipe.transform(null)).toBe(null);
|
||||
});
|
||||
|
||||
it('should not transform when missing node entry', () => {
|
||||
expect(pipe.transform({} as any)).toBe(null);
|
||||
});
|
||||
|
||||
it('should use title and description when all fields present', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeTitle,
|
||||
'cm:description': nodeDescription
|
||||
}
|
||||
}
|
||||
};
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(`${nodeTitle}\n${nodeDescription}`);
|
||||
});
|
||||
|
||||
it('should use name when other properties are missing', () => {
|
||||
const node = {
|
||||
entry: {
|
||||
name: nodeName
|
||||
}
|
||||
} as NodeEntry;
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should display name when title and description are missing', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {}
|
||||
}
|
||||
};
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should use name and description when title is missing', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': null,
|
||||
'cm:description': nodeDescription
|
||||
}
|
||||
}
|
||||
};
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(`${nodeName}\n${nodeDescription}`);
|
||||
});
|
||||
|
||||
it('should use name and title when description is missing', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeTitle,
|
||||
'cm:description': null
|
||||
}
|
||||
}
|
||||
};
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(`${nodeName}\n${nodeTitle}`);
|
||||
});
|
||||
|
||||
it('should use name if name and description are the same', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': null,
|
||||
'cm:description': nodeName
|
||||
}
|
||||
}
|
||||
};
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should use name if name and title are the same', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeName,
|
||||
'cm:description': null
|
||||
}
|
||||
}
|
||||
};
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should use name if all values are the same', () => {
|
||||
const node: any = {
|
||||
entry: {
|
||||
name: nodeName,
|
||||
properties: {
|
||||
'cm:title': nodeName,
|
||||
'cm:description': nodeName
|
||||
}
|
||||
}
|
||||
};
|
||||
const tooltip = pipe.transform(node);
|
||||
expect(tooltip).toBe(nodeName);
|
||||
});
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
|
||||
@Pipe({
|
||||
name: 'adfNodeNameTooltip'
|
||||
})
|
||||
export class NodeNameTooltipPipe implements PipeTransform {
|
||||
transform(node: NodeEntry): string {
|
||||
if (node) {
|
||||
return this.getNodeTooltip(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private containsLine(lines: string[], line: string): boolean {
|
||||
return lines.some((item: string) => item.toLowerCase() === line.toLowerCase());
|
||||
}
|
||||
|
||||
private removeDuplicateLines(lines: string[]): string[] {
|
||||
const reducer = (acc: string[], line: string): string[] => {
|
||||
if (!this.containsLine(acc, line)) {
|
||||
acc.push(line);
|
||||
}
|
||||
return acc;
|
||||
};
|
||||
|
||||
return lines.reduce(reducer, []);
|
||||
}
|
||||
|
||||
private getNodeTooltip(node: NodeEntry): string {
|
||||
if (!node?.entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
entry: { properties, name }
|
||||
} = node;
|
||||
const lines = [name];
|
||||
|
||||
if (properties) {
|
||||
const { 'cm:title': title, 'cm:description': description } = properties;
|
||||
|
||||
if (title && description) {
|
||||
lines[0] = title;
|
||||
lines[1] = description;
|
||||
}
|
||||
|
||||
if (title) {
|
||||
lines[1] = title;
|
||||
}
|
||||
|
||||
if (description) {
|
||||
lines[1] = description;
|
||||
}
|
||||
}
|
||||
|
||||
return this.removeDuplicateLines(lines).join(`\n`);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './node-name-tooltip.pipe';
|
||||
export * from './content-pipe.module';
|
||||
+2
-1
@@ -79,6 +79,8 @@ export class SearchDateRangeComponent implements OnInit {
|
||||
@Output()
|
||||
valid = new EventEmitter<boolean>();
|
||||
|
||||
private readonly formBuilder = inject(FormBuilder);
|
||||
|
||||
form = this.formBuilder.group<SearchDateRange>({
|
||||
dateRangeType: DateRangeType.ANY,
|
||||
inLastValueType: InLastDateType.DAYS,
|
||||
@@ -96,7 +98,6 @@ export class SearchDateRangeComponent implements OnInit {
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private userPreferencesService: UserPreferencesService,
|
||||
private dateAdapter: DateAdapter<DateFnsAdapter>,
|
||||
@Inject(MAT_DATE_FORMATS) private dateFormatConfig: MatDateFormats
|
||||
|
||||
+3
-4
@@ -59,6 +59,8 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
|
||||
autocompleteOptions: AutocompleteOption[] = [];
|
||||
preselectedOptions: AutocompleteOption[] = [];
|
||||
|
||||
private readonly formBuilder = inject(FormBuilder);
|
||||
|
||||
private _form = this.formBuilder.nonNullable.group<FileSizeCondition>({
|
||||
fileSizeOperator: FileSizeOperator.AT_LEAST,
|
||||
fileSize: undefined,
|
||||
@@ -106,10 +108,7 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor(
|
||||
private readonly formBuilder: FormBuilder,
|
||||
private readonly translateService: TranslateService
|
||||
) {}
|
||||
constructor(private readonly translateService: TranslateService) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.settings) {
|
||||
|
||||
@@ -36,7 +36,6 @@ export * from './lib/node-comments/index';
|
||||
export * from './lib/new-version-uploader';
|
||||
export * from './lib/interfaces/index';
|
||||
export * from './lib/version-compatibility/index';
|
||||
export * from './lib/pipes/index';
|
||||
export * from './lib/common/index';
|
||||
export * from './lib/tree/index';
|
||||
export * from './lib/category/index';
|
||||
|
||||
Reference in New Issue
Block a user