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:
@@ -178,7 +178,6 @@ A collection of Angular components for generic use.
|
||||
| [Full name pipe](core/pipes/full-name.pipe.md) | Joins the first and last name properties from a `UserLike` object into a single string. | [Source](../lib/core/src/lib/pipes/full-name.pipe.ts) |
|
||||
| [Localized Date pipe](core/pipes/localized-date.pipe.md) | Converts a date to a given format and locale. | [Source](../lib/core/src/lib/pipes/localized-date.pipe.ts) |
|
||||
| [Multi Value Pipe](core/pipes/multi-value.pipe.md) | Takes an array of strings and turns it into one string where items are separated by a separator. The default separator applied to the list is the comma , however, you can set your own separator in the params of the pipe. | [Source](../lib/core/src/lib/pipes/multi-value.pipe.ts) |
|
||||
| [Node Name Tooltip pipe](core/pipes/node-name-tooltip.pipe.md) | Formats the tooltip for a Node. | [Source](../lib/content-services/src/lib/pipes/node-name-tooltip.pipe.ts) |
|
||||
| [Text Highlight pipe](core/pipes/text-highlight.pipe.md) | Adds highlighting to words or sections of text that match a search string. | [Source](../lib/core/src/lib/pipes/text-highlight.pipe.ts) |
|
||||
| [Time Ago pipe](core/pipes/time-ago.pipe.md) | Converts a recent past date into a number of days ago. | [Source](../lib/core/src/lib/pipes/time-ago.pipe.ts) |
|
||||
| [User Initial pipe](core/pipes/user-initial.pipe.md) | Takes the name fields of a `UserLike` object and extracts and formats the initials. | [Source](../lib/core/src/lib/pipes/user-initial.pipe.ts) |
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
Title: Node Name Tooltip pipe
|
||||
Added: v2.0.0
|
||||
Status: Active
|
||||
---
|
||||
|
||||
# [Node Name Tooltip pipe](../../../lib/content-services/src/lib/pipes/node-name-tooltip.pipe.ts "Defined in node-name-tooltip.pipe.ts")
|
||||
|
||||
Formats the tooltip for a [`Node`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/Node.md).
|
||||
|
||||
## Basic Usage
|
||||
|
||||
<!-- {% raw %} -->
|
||||
|
||||
```html
|
||||
<data-column
|
||||
key="name"
|
||||
title="Name">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
```
|
||||
|
||||
<!-- {% endraw %} -->
|
||||
|
||||
## Details
|
||||
|
||||
The tooltip is formatted according to the following rules:
|
||||
|
||||
- if the _title_ and _description_ are missing, then the tooltip shows the _name_;
|
||||
- if the _title_ is missing, then the tooltip shows the _name_ and _description_;
|
||||
- if the _description_ is missing, then the tooltip shows the _name_ and _title_;
|
||||
- if _name_ and _title_, _name_ and _description_, or _title_ and _description_ are the same, then only a single line is displayed.
|
||||
@@ -605,7 +605,6 @@ backend services have been tested with each released version of ADF.
|
||||
- [Logout directive](core/directives/logout.directive.md)
|
||||
- [Node delete directive](content-services/directives/node-delete.directive.md)
|
||||
- [Node favorite directive](content-services/directives/node-favorite.directive.md)
|
||||
- [Node name tooltip pipe](core/pipes/node-name-tooltip.pipe.md)
|
||||
- [Node permission service](content-services/services/node-permission.service.md)
|
||||
- [Node restore directive](content-services/directives/node-restore.directive.md)
|
||||
- [Nodes api service](core/services/nodes-api.service.md)
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
|
||||
import { Observable, defer, EMPTY, combineLatest } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
@@ -33,17 +33,7 @@ import { HttpHeaders } from '@angular/common/http';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
constructor(
|
||||
appConfig: AppConfigService,
|
||||
cookie: CookieService,
|
||||
private jwtHelperService: JwtHelperService,
|
||||
private authStorage: OAuthStorage,
|
||||
private oauthService: OAuthService,
|
||||
private readonly authConfig: AuthConfigService,
|
||||
private readonly auth: AuthService
|
||||
) {
|
||||
super(appConfig, cookie);
|
||||
}
|
||||
private readonly auth = inject(AuthService);
|
||||
|
||||
/**
|
||||
* Observable that determines whether an SSO login should be performed.
|
||||
@@ -56,6 +46,17 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
map(([authenticated, isDiscoveryDocumentLoaded]) => !authenticated && isDiscoveryDocumentLoaded)
|
||||
);
|
||||
|
||||
constructor(
|
||||
appConfig: AppConfigService,
|
||||
cookie: CookieService,
|
||||
private jwtHelperService: JwtHelperService,
|
||||
private authStorage: OAuthStorage,
|
||||
private oauthService: OAuthService,
|
||||
private readonly authConfig: AuthConfigService
|
||||
) {
|
||||
super(appConfig, cookie);
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return this.oauthService.hasValidAccessToken() && this.oauthService.hasValidIdToken();
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ import { MatError } from '@angular/material/form-field';
|
||||
})
|
||||
export class CardViewBoolItemComponent extends BaseCardView<CardViewBoolItemModel> {
|
||||
@Input()
|
||||
editable: boolean;
|
||||
declare editable: boolean;
|
||||
|
||||
private _error: string;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface CardViewArrayItem {
|
||||
|
||||
export class CardViewArrayItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||
type: string = 'array';
|
||||
value: Observable<CardViewArrayItem[]>;
|
||||
declare value: Observable<CardViewArrayItem[]>;
|
||||
noOfItemsToDisplay: number;
|
||||
|
||||
constructor(cardViewArrayItemProperties: CardViewArrayItemProperties) {
|
||||
|
||||
@@ -23,7 +23,7 @@ import { CardViewBoolItemProperties } from '../interfaces/card-view.interfaces';
|
||||
export class CardViewBoolItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||
type = 'bool';
|
||||
value = false;
|
||||
default: boolean;
|
||||
declare default: boolean;
|
||||
|
||||
constructor(cardViewBoolItemProperties: CardViewBoolItemProperties) {
|
||||
super(cardViewBoolItemProperties);
|
||||
|
||||
@@ -21,7 +21,7 @@ import { CardViewBaseItemModel } from './card-view-baseitem.model';
|
||||
|
||||
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||
type = 'map';
|
||||
value: Map<string, string>;
|
||||
declare value: Map<string, string>;
|
||||
|
||||
get displayValue() {
|
||||
if (this.value && this.value.size > 0) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { DataRow } from '../../data/data-row.model';
|
||||
import { DataTableAdapter } from '../../data/datatable-adapter';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { DataTableService } from '../../services/datatable.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { ClipboardDirective } from '../../../clipboard/clipboard.directive';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { TruncatePipe } from '../../../pipes/truncate.pipe';
|
||||
@@ -29,7 +29,7 @@ import { UserPreferencesService } from '../../../common/services/user-preference
|
||||
|
||||
@Component({
|
||||
selector: 'adf-datatable-cell',
|
||||
imports: [CommonModule, ClipboardDirective, TruncatePipe],
|
||||
imports: [ClipboardDirective, TruncatePipe, AsyncPipe],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `
|
||||
@let value = value$ | async;
|
||||
|
||||
@@ -23,7 +23,7 @@ import { ContainerColumnModel } from './container-column.model';
|
||||
import { FormFieldTypes } from './form-field-types';
|
||||
|
||||
export class ContainerModel extends FormWidgetModel {
|
||||
field: FormFieldModel;
|
||||
declare field: FormFieldModel;
|
||||
|
||||
readonly columns: ContainerColumnModel[] = [];
|
||||
isExpanded: boolean = true;
|
||||
|
||||
@@ -52,12 +52,12 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
private readonly defaultEmptyOptionName = 'Choose one...';
|
||||
|
||||
// model members
|
||||
fieldType: string;
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
declare fieldType: string;
|
||||
declare id: string;
|
||||
declare name: string;
|
||||
declare type: string;
|
||||
overrideId: boolean;
|
||||
tab: string;
|
||||
declare tab: string;
|
||||
rowspan: number = 1;
|
||||
colspan: number = 1;
|
||||
placeholder: string = null;
|
||||
@@ -98,7 +98,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
variableConfig: VariableConfig;
|
||||
schemaDefinition: DataColumn[];
|
||||
externalProperty?: string;
|
||||
style?: string;
|
||||
declare style?: string;
|
||||
parent?: RepeatableSectionModel;
|
||||
|
||||
// container model members
|
||||
|
||||
@@ -28,14 +28,14 @@ export class TaskListCloudSortingModel {
|
||||
}
|
||||
|
||||
export class TaskListRequestSortingModel extends TaskListCloudSortingModel {
|
||||
orderBy: string;
|
||||
direction: string;
|
||||
declare orderBy: string;
|
||||
declare direction: string;
|
||||
|
||||
isFieldProcessVariable: boolean;
|
||||
processVariableData?: {
|
||||
processDefinitionKey: string;
|
||||
type: string;
|
||||
}
|
||||
};
|
||||
|
||||
constructor(obj: TaskListRequestSortingModel) {
|
||||
super(obj);
|
||||
|
||||
@@ -51,7 +51,7 @@ export const mockPreselectedFoodUsers = [
|
||||
|
||||
@Injectable()
|
||||
export class IdentityUserServiceMock extends IdentityUserService {
|
||||
queryParams: { search: string; application?: string; roles?: string[]; groups?: string[] };
|
||||
declare queryParams: { search: string; application?: string; roles?: string[]; groups?: string[] };
|
||||
|
||||
getCurrentUserInfo(): IdentityUserModel {
|
||||
return mockKielbasaSausage;
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@
|
||||
export class ProcessListCloudSortingModel {
|
||||
orderBy: string;
|
||||
direction: string;
|
||||
constructor(obj: any) {
|
||||
constructor(obj: any) {
|
||||
if (obj) {
|
||||
this.orderBy = obj.orderBy;
|
||||
this.direction = obj.direction;
|
||||
@@ -26,14 +26,14 @@ export class ProcessListCloudSortingModel {
|
||||
}
|
||||
}
|
||||
export class ProcessListRequestSortingModel extends ProcessListCloudSortingModel {
|
||||
orderBy: string;
|
||||
direction: string;
|
||||
declare orderBy: string;
|
||||
declare direction: string;
|
||||
|
||||
isFieldProcessVariable: boolean;
|
||||
processVariableData?: {
|
||||
processDefinitionKey: string;
|
||||
type: string;
|
||||
}
|
||||
};
|
||||
|
||||
constructor(obj: ProcessListRequestSortingModel) {
|
||||
super(obj);
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
|
||||
processVariableFilters: ProcessVariableFilterModel[];
|
||||
|
||||
rows: TaskInstanceCloudListViewModel[] = [];
|
||||
dataAdapter: TasksListDatatableAdapter | undefined;
|
||||
declare dataAdapter: TasksListDatatableAdapter | undefined;
|
||||
|
||||
private isReloadingSubject$ = new BehaviorSubject<boolean>(false);
|
||||
isLoading$ = combineLatest([this.isLoadingPreferences$, this.isReloadingSubject$]).pipe(
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
},
|
||||
"tasksRunnerOptions": {
|
||||
"default": {
|
||||
"runner": "nx/tasks-runners/default",
|
||||
"options": {
|
||||
"runtimeCacheInputs": ["node -v"]
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
"version": "8.3.0",
|
||||
"author": "Hyland Software, Inc. and its affiliates",
|
||||
"scripts": {
|
||||
"prepare": "husky install",
|
||||
"prepare": "husky",
|
||||
"bundle:js-api": "nx run js-api:bundle",
|
||||
"bundle:cli": "nx run cli:bundle",
|
||||
"test:affected": "nx affected:test",
|
||||
|
||||
Reference in New Issue
Block a user