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) |
|
| [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) |
|
| [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) |
|
| [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) |
|
| [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) |
|
| [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) |
|
| [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)
|
- [Logout directive](core/directives/logout.directive.md)
|
||||||
- [Node delete directive](content-services/directives/node-delete.directive.md)
|
- [Node delete directive](content-services/directives/node-delete.directive.md)
|
||||||
- [Node favorite directive](content-services/directives/node-favorite.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 permission service](content-services/services/node-permission.service.md)
|
||||||
- [Node restore directive](content-services/directives/node-restore.directive.md)
|
- [Node restore directive](content-services/directives/node-restore.directive.md)
|
||||||
- [Nodes api service](core/services/nodes-api.service.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 {
|
export class DropdownBreadcrumbComponent extends BreadcrumbComponent implements OnChanges {
|
||||||
@ViewChild('dropdown')
|
@ViewChild('dropdown')
|
||||||
dropdown: MatSelect;
|
declare dropdown: MatSelect;
|
||||||
|
|
||||||
currentNode: PathElement;
|
currentNode: PathElement;
|
||||||
previousNodes: PathElement[];
|
declare previousNodes: PathElement[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the current and previous nodes from the route array
|
* 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 { ASPECT_LIST_DIRECTIVES } from './aspect-list/aspect-list.module';
|
||||||
import { versionCompatibilityFactory } from './version-compatibility/version-compatibility-factory';
|
import { versionCompatibilityFactory } from './version-compatibility/version-compatibility-factory';
|
||||||
import { VersionCompatibilityService } from './version-compatibility/version-compatibility.service';
|
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 { contentAuthLoaderFactory } from './auth-loader/content-auth-loader-factory';
|
||||||
import { ContentAuthLoaderService } from './auth-loader/content-auth-loader.service';
|
import { ContentAuthLoaderService } from './auth-loader/content-auth-loader.service';
|
||||||
import { CategoriesManagementComponent } from './category';
|
import { CategoriesManagementComponent } from './category';
|
||||||
@@ -55,7 +54,6 @@ import { AlfrescoApiLoaderService, createAlfrescoApiInstance } from './api-facto
|
|||||||
MaterialModule,
|
MaterialModule,
|
||||||
MatDatetimepickerModule,
|
MatDatetimepickerModule,
|
||||||
MatNativeDatetimeModule,
|
MatNativeDatetimeModule,
|
||||||
...CONTENT_PIPES,
|
|
||||||
...CONTENT_TAG_DIRECTIVES,
|
...CONTENT_TAG_DIRECTIVES,
|
||||||
...CONTENT_DIALOG_DIRECTIVES,
|
...CONTENT_DIALOG_DIRECTIVES,
|
||||||
...CONTENT_SEARCH_DIRECTIVES,
|
...CONTENT_SEARCH_DIRECTIVES,
|
||||||
@@ -82,7 +80,6 @@ import { AlfrescoApiLoaderService, createAlfrescoApiInstance } from './api-facto
|
|||||||
providers: [provideTranslations('adf-content-services', 'assets/adf-content-services')],
|
providers: [provideTranslations('adf-content-services', 'assets/adf-content-services')],
|
||||||
exports: [
|
exports: [
|
||||||
MaterialModule,
|
MaterialModule,
|
||||||
...CONTENT_PIPES,
|
|
||||||
...CONTENT_TAG_DIRECTIVES,
|
...CONTENT_TAG_DIRECTIVES,
|
||||||
...DOCUMENT_LIST_DIRECTIVES,
|
...DOCUMENT_LIST_DIRECTIVES,
|
||||||
...CONTENT_UPLOAD_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')];
|
DEFAULT_SORTING: DataSorting[] = [new DataSorting('name', 'asc'), new DataSorting('isFolder', 'desc')];
|
||||||
|
|
||||||
@ContentChild(DataColumnListComponent)
|
@ContentChild(DataColumnListComponent)
|
||||||
columnList: DataColumnListComponent;
|
declare columnList: DataColumnListComponent;
|
||||||
|
|
||||||
@ContentChild(CustomLoadingContentTemplateDirective)
|
@ContentChild(CustomLoadingContentTemplateDirective)
|
||||||
customLoadingContent: 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 { 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 { ShareDataRow } from '../../data/share-data-row.model';
|
||||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-library-name-column',
|
selector: 'adf-library-name-column',
|
||||||
@@ -62,7 +63,10 @@ export class LibraryNameColumnComponent implements OnInit {
|
|||||||
|
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
constructor(private element: ElementRef, private nodesApiService: NodesApiService) {}
|
constructor(
|
||||||
|
private element: ElementRef,
|
||||||
|
private nodesApiService: NodesApiService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
@@ -84,8 +88,9 @@ export class LibraryNameColumnComponent implements OnInit {
|
|||||||
this.node = this.context.row.node;
|
this.node = this.context.row.node;
|
||||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
||||||
if (this.node?.entry) {
|
if (this.node?.entry) {
|
||||||
this.displayText$.next(this.makeLibraryTitle(this.node.entry as any, rows));
|
const allEntries = rows.map((row: ShareDataRow) => row.node.entry);
|
||||||
this.displayTooltip$.next(this.makeLibraryTooltip(this.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' } } }
|
row: { node: { entry: { role: 'SiteManager' } } }
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = '';
|
component.ngOnInit();
|
||||||
component.displayText$.subscribe((val) => (value = val));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(value).toBe('LIBRARY.ROLE.MANAGER');
|
|
||||||
|
expect(component.displayText()).toBe('LIBRARY.ROLE.MANAGER');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Collaborator', () => {
|
it('should render Collaborator', () => {
|
||||||
@@ -47,11 +46,10 @@ describe('LibraryRoleColumnComponent', () => {
|
|||||||
row: { node: { entry: { role: 'SiteCollaborator' } } }
|
row: { node: { entry: { role: 'SiteCollaborator' } } }
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = '';
|
component.ngOnInit();
|
||||||
component.displayText$.subscribe((val) => (value = val));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(value).toBe('LIBRARY.ROLE.COLLABORATOR');
|
|
||||||
|
expect(component.displayText()).toBe('LIBRARY.ROLE.COLLABORATOR');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Contributor', () => {
|
it('should render Contributor', () => {
|
||||||
@@ -59,11 +57,10 @@ describe('LibraryRoleColumnComponent', () => {
|
|||||||
row: { node: { entry: { role: 'SiteContributor' } } }
|
row: { node: { entry: { role: 'SiteContributor' } } }
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = '';
|
component.ngOnInit();
|
||||||
component.displayText$.subscribe((val) => (value = val));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(value).toBe('LIBRARY.ROLE.CONTRIBUTOR');
|
|
||||||
|
expect(component.displayText()).toBe('LIBRARY.ROLE.CONTRIBUTOR');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render Consumer', () => {
|
it('should render Consumer', () => {
|
||||||
@@ -71,11 +68,10 @@ describe('LibraryRoleColumnComponent', () => {
|
|||||||
row: { node: { entry: { role: 'SiteConsumer' } } }
|
row: { node: { entry: { role: 'SiteConsumer' } } }
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = '';
|
component.ngOnInit();
|
||||||
component.displayText$.subscribe((val) => (value = val));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(value).toBe('LIBRARY.ROLE.CONSUMER');
|
|
||||||
|
expect(component.displayText()).toBe('LIBRARY.ROLE.CONSUMER');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not render text for unknown', () => {
|
it('should not render text for unknown', () => {
|
||||||
@@ -83,11 +79,10 @@ describe('LibraryRoleColumnComponent', () => {
|
|||||||
row: { node: { entry: { role: 'ROLE' } } }
|
row: { node: { entry: { role: 'ROLE' } } }
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = '';
|
component.ngOnInit();
|
||||||
component.displayText$.subscribe((val) => (value = val));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
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', () => {
|
it('should take role from obj when node entry role is not provided', () => {
|
||||||
@@ -98,10 +93,9 @@ describe('LibraryRoleColumnComponent', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = '';
|
component.ngOnInit();
|
||||||
component.displayText$.subscribe((val) => (value = val));
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ChangeDetectionStrategy, Component, DestroyRef, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, computed, DestroyRef, inject, Input, OnInit, signal, ViewEncapsulation } from '@angular/core';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
|
||||||
import { Site } from '@alfresco/js-api';
|
import { Site } from '@alfresco/js-api';
|
||||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||||
import { AsyncPipe } from '@angular/common';
|
|
||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-library-role-column',
|
selector: 'adf-library-role-column',
|
||||||
imports: [AsyncPipe, TranslatePipe],
|
imports: [TranslatePipe],
|
||||||
template: `
|
template: `
|
||||||
<span class="adf-datatable-cell-value" title="{{ displayText$ | async | translate }}">
|
<span class="adf-datatable-cell-value" [title]="displayText() | translate">
|
||||||
{{ displayText$ | async | translate }}
|
{{ displayText() | translate }}
|
||||||
</span>
|
</span>
|
||||||
`,
|
`,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
@@ -40,7 +38,23 @@ export class LibraryRoleColumnComponent implements OnInit {
|
|||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
context: any;
|
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);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
@@ -63,23 +77,7 @@ export class LibraryRoleColumnComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected updateValue() {
|
protected updateValue() {
|
||||||
const role = this.context.row.node?.entry.role ?? this.context.row.obj.role;
|
const roleValue = this.context.row.node?.entry.role ?? this.context.row.obj.role;
|
||||||
switch (role) {
|
this.role.set(roleValue);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+153
-11
@@ -18,8 +18,13 @@
|
|||||||
import { NameColumnComponent } from './name-column.component';
|
import { NameColumnComponent } from './name-column.component';
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { skip } from 'rxjs/operators';
|
import { skip } from 'rxjs/operators';
|
||||||
|
import { NodeEntry } from '@alfresco/js-api';
|
||||||
|
|
||||||
describe('NameColumnComponent', () => {
|
describe('NameColumnComponent', () => {
|
||||||
|
const nodeName = 'node-name';
|
||||||
|
const nodeTitle = 'node-title';
|
||||||
|
const nodeDescription = 'node-description';
|
||||||
|
|
||||||
let fixture: ComponentFixture<NameColumnComponent>;
|
let fixture: ComponentFixture<NameColumnComponent>;
|
||||||
let context: any;
|
let context: any;
|
||||||
let component: NameColumnComponent;
|
let component: NameColumnComponent;
|
||||||
@@ -42,22 +47,159 @@ describe('NameColumnComponent', () => {
|
|||||||
component.context = context;
|
component.context = context;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the display value based on default key', (done) => {
|
describe('Display Text', () => {
|
||||||
component.displayText$.pipe(skip(1)).subscribe((value) => {
|
it('should set the display value based on default key', (done) => {
|
||||||
expect(value).toBe('name');
|
component.displayText$.pipe(skip(1)).subscribe((value) => {
|
||||||
done();
|
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) => {
|
describe('Tooltip Logic', () => {
|
||||||
component.key = 'title';
|
it('should return null when missing node', () => {
|
||||||
component.displayText$.pipe(skip(1)).subscribe((value) => {
|
component.context.row.node = null;
|
||||||
expect(value).toBe('title');
|
component.ngOnInit();
|
||||||
done();
|
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.
|
* 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 { NodeEntry } from '@alfresco/js-api';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import { NodeNameTooltipPipe } from '../../../pipes/node-name-tooltip.pipe';
|
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-name-column',
|
selector: 'adf-name-column',
|
||||||
imports: [AsyncPipe, TranslatePipe, NodeNameTooltipPipe],
|
imports: [AsyncPipe, TranslatePipe],
|
||||||
template: `
|
template: `
|
||||||
<span
|
<span
|
||||||
role="link"
|
role="link"
|
||||||
@@ -39,7 +39,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|||||||
}
|
}
|
||||||
"
|
"
|
||||||
class="adf-datatable-cell-value"
|
class="adf-datatable-cell-value"
|
||||||
title="{{ node | adfNodeNameTooltip }}"
|
[title]="tooltip()"
|
||||||
(click)="onClick()"
|
(click)="onClick()"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
(keyup.enter)="onClick()"
|
(keyup.enter)="onClick()"
|
||||||
@@ -53,6 +53,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|||||||
})
|
})
|
||||||
export class NameColumnComponent implements OnInit {
|
export class NameColumnComponent implements OnInit {
|
||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
context: any;
|
context: any;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@@ -61,9 +62,14 @@ export class NameColumnComponent implements OnInit {
|
|||||||
displayText$ = new BehaviorSubject<string>('');
|
displayText$ = new BehaviorSubject<string>('');
|
||||||
node: NodeEntry;
|
node: NodeEntry;
|
||||||
|
|
||||||
|
readonly tooltip = computed(() => NodeTooltipUtils.getNodeTooltip(this.node));
|
||||||
|
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
constructor(private element: ElementRef, private nodesApiService: NodesApiService) {}
|
constructor(
|
||||||
|
private element: ElementRef,
|
||||||
|
private nodesApiService: NodesApiService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.updateValue();
|
this.updateValue();
|
||||||
@@ -85,8 +91,8 @@ export class NameColumnComponent implements OnInit {
|
|||||||
this.node = this.context.row.node;
|
this.node = this.context.row.node;
|
||||||
|
|
||||||
if (this.node?.entry) {
|
if (this.node?.entry) {
|
||||||
const displayText = this.context.row.getValue(this.key);
|
const displayValue = this.context.row.getValue(this.key);
|
||||||
this.displayText$.next(displayText || this.node.entry.id);
|
this.displayText$.next(displayValue || this.node.entry.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-31
@@ -15,36 +15,29 @@
|
|||||||
* limitations under the License.
|
* 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 { NodeEntry } from '@alfresco/js-api';
|
||||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||||
import { CommonModule } from '@angular/common';
|
import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
|
||||||
import { NodeNameTooltipPipe } from '../../../pipes/node-name-tooltip.pipe';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-trashcan-name-column',
|
selector: 'adf-trashcan-name-column',
|
||||||
imports: [CommonModule, NodeNameTooltipPipe],
|
template: `<span class="adf-datatable-cell-value" [title]="tooltip()">{{ displayText }}</span>`,
|
||||||
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>
|
|
||||||
`,
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { class: 'adf-datatable-content-cell adf-trashcan-name-column' }
|
host: { class: 'adf-datatable-content-cell adf-trashcan-name-column' }
|
||||||
})
|
})
|
||||||
export class TrashcanNameColumnComponent implements OnInit {
|
export class TrashcanNameColumnComponent implements OnInit {
|
||||||
@Input({ required: true })
|
@Input({ required: true })
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
context: any;
|
context: any;
|
||||||
|
|
||||||
isLibrary = false;
|
isLibrary = false;
|
||||||
displayText: string;
|
displayText: string;
|
||||||
displayTooltip: string;
|
|
||||||
node: NodeEntry;
|
node: NodeEntry;
|
||||||
|
|
||||||
|
readonly tooltip = computed(() => (this.isLibrary ? NodeTooltipUtils.getLibraryTooltip(this.node) : NodeTooltipUtils.getNodeTooltip(this.node)));
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.node = this.context.row.node;
|
this.node = this.context.row.node;
|
||||||
const rows: Array<ShareDataRow> = this.context.data.rows || [];
|
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';
|
this.isLibrary = this.node.entry.nodeType === 'st:site';
|
||||||
|
|
||||||
if (this.isLibrary) {
|
if (this.isLibrary) {
|
||||||
const { properties } = this.node.entry;
|
const allEntries = rows.map((row) => row.node.entry);
|
||||||
|
this.displayText = NodeTooltipUtils.getLibraryTitle(this.node.entry, allEntries);
|
||||||
this.displayText = this.makeLibraryTitle(this.node.entry, rows);
|
|
||||||
this.displayTooltip = properties['cm:description'] || properties['cm:title'];
|
|
||||||
} else {
|
} else {
|
||||||
this.displayText = this.node.entry.name || this.node.entry.id;
|
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';
|
export * from './interfaces/document-list-loader.interface';
|
||||||
|
|
||||||
|
// utils
|
||||||
|
export * from './utils/node-tooltip.utils';
|
||||||
|
|
||||||
export * from './document-list.module';
|
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()
|
@Output()
|
||||||
valid = new EventEmitter<boolean>();
|
valid = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
private readonly formBuilder = inject(FormBuilder);
|
||||||
|
|
||||||
form = this.formBuilder.group<SearchDateRange>({
|
form = this.formBuilder.group<SearchDateRange>({
|
||||||
dateRangeType: DateRangeType.ANY,
|
dateRangeType: DateRangeType.ANY,
|
||||||
inLastValueType: InLastDateType.DAYS,
|
inLastValueType: InLastDateType.DAYS,
|
||||||
@@ -96,7 +98,6 @@ export class SearchDateRangeComponent implements OnInit {
|
|||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private formBuilder: FormBuilder,
|
|
||||||
private userPreferencesService: UserPreferencesService,
|
private userPreferencesService: UserPreferencesService,
|
||||||
private dateAdapter: DateAdapter<DateFnsAdapter>,
|
private dateAdapter: DateAdapter<DateFnsAdapter>,
|
||||||
@Inject(MAT_DATE_FORMATS) private dateFormatConfig: MatDateFormats
|
@Inject(MAT_DATE_FORMATS) private dateFormatConfig: MatDateFormats
|
||||||
|
|||||||
+3
-4
@@ -59,6 +59,8 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
|
|||||||
autocompleteOptions: AutocompleteOption[] = [];
|
autocompleteOptions: AutocompleteOption[] = [];
|
||||||
preselectedOptions: AutocompleteOption[] = [];
|
preselectedOptions: AutocompleteOption[] = [];
|
||||||
|
|
||||||
|
private readonly formBuilder = inject(FormBuilder);
|
||||||
|
|
||||||
private _form = this.formBuilder.nonNullable.group<FileSizeCondition>({
|
private _form = this.formBuilder.nonNullable.group<FileSizeCondition>({
|
||||||
fileSizeOperator: FileSizeOperator.AT_LEAST,
|
fileSizeOperator: FileSizeOperator.AT_LEAST,
|
||||||
fileSize: undefined,
|
fileSize: undefined,
|
||||||
@@ -106,10 +108,7 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
|
|||||||
|
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
constructor(
|
constructor(private readonly translateService: TranslateService) {}
|
||||||
private readonly formBuilder: FormBuilder,
|
|
||||||
private readonly translateService: TranslateService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.settings) {
|
if (this.settings) {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ export * from './lib/node-comments/index';
|
|||||||
export * from './lib/new-version-uploader';
|
export * from './lib/new-version-uploader';
|
||||||
export * from './lib/interfaces/index';
|
export * from './lib/interfaces/index';
|
||||||
export * from './lib/version-compatibility/index';
|
export * from './lib/version-compatibility/index';
|
||||||
export * from './lib/pipes/index';
|
|
||||||
export * from './lib/common/index';
|
export * from './lib/common/index';
|
||||||
export * from './lib/tree/index';
|
export * from './lib/tree/index';
|
||||||
export * from './lib/category/index';
|
export * from './lib/category/index';
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable, inject } from '@angular/core';
|
||||||
import { OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
|
import { OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
|
||||||
import { Observable, defer, EMPTY, combineLatest } from 'rxjs';
|
import { Observable, defer, EMPTY, combineLatest } from 'rxjs';
|
||||||
import { catchError, map } from 'rxjs/operators';
|
import { catchError, map } from 'rxjs/operators';
|
||||||
@@ -33,17 +33,7 @@ import { HttpHeaders } from '@angular/common/http';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class OidcAuthenticationService extends BaseAuthenticationService {
|
export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||||
constructor(
|
private readonly auth = inject(AuthService);
|
||||||
appConfig: AppConfigService,
|
|
||||||
cookie: CookieService,
|
|
||||||
private jwtHelperService: JwtHelperService,
|
|
||||||
private authStorage: OAuthStorage,
|
|
||||||
private oauthService: OAuthService,
|
|
||||||
private readonly authConfig: AuthConfigService,
|
|
||||||
private readonly auth: AuthService
|
|
||||||
) {
|
|
||||||
super(appConfig, cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observable that determines whether an SSO login should be performed.
|
* Observable that determines whether an SSO login should be performed.
|
||||||
@@ -56,6 +46,17 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
|||||||
map(([authenticated, isDiscoveryDocumentLoaded]) => !authenticated && isDiscoveryDocumentLoaded)
|
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 {
|
isLoggedIn(): boolean {
|
||||||
return this.oauthService.hasValidAccessToken() && this.oauthService.hasValidIdToken();
|
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> {
|
export class CardViewBoolItemComponent extends BaseCardView<CardViewBoolItemModel> {
|
||||||
@Input()
|
@Input()
|
||||||
editable: boolean;
|
declare editable: boolean;
|
||||||
|
|
||||||
private _error: string;
|
private _error: string;
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export interface CardViewArrayItem {
|
|||||||
|
|
||||||
export class CardViewArrayItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
export class CardViewArrayItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||||
type: string = 'array';
|
type: string = 'array';
|
||||||
value: Observable<CardViewArrayItem[]>;
|
declare value: Observable<CardViewArrayItem[]>;
|
||||||
noOfItemsToDisplay: number;
|
noOfItemsToDisplay: number;
|
||||||
|
|
||||||
constructor(cardViewArrayItemProperties: CardViewArrayItemProperties) {
|
constructor(cardViewArrayItemProperties: CardViewArrayItemProperties) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { CardViewBoolItemProperties } from '../interfaces/card-view.interfaces';
|
|||||||
export class CardViewBoolItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
export class CardViewBoolItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||||
type = 'bool';
|
type = 'bool';
|
||||||
value = false;
|
value = false;
|
||||||
default: boolean;
|
declare default: boolean;
|
||||||
|
|
||||||
constructor(cardViewBoolItemProperties: CardViewBoolItemProperties) {
|
constructor(cardViewBoolItemProperties: CardViewBoolItemProperties) {
|
||||||
super(cardViewBoolItemProperties);
|
super(cardViewBoolItemProperties);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { CardViewBaseItemModel } from './card-view-baseitem.model';
|
|||||||
|
|
||||||
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||||
type = 'map';
|
type = 'map';
|
||||||
value: Map<string, string>;
|
declare value: Map<string, string>;
|
||||||
|
|
||||||
get displayValue() {
|
get displayValue() {
|
||||||
if (this.value && this.value.size > 0) {
|
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 { DataTableAdapter } from '../../data/datatable-adapter';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
import { DataTableService } from '../../services/datatable.service';
|
import { DataTableService } from '../../services/datatable.service';
|
||||||
import { CommonModule } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
import { ClipboardDirective } from '../../../clipboard/clipboard.directive';
|
import { ClipboardDirective } from '../../../clipboard/clipboard.directive';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { TruncatePipe } from '../../../pipes/truncate.pipe';
|
import { TruncatePipe } from '../../../pipes/truncate.pipe';
|
||||||
@@ -29,7 +29,7 @@ import { UserPreferencesService } from '../../../common/services/user-preference
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-datatable-cell',
|
selector: 'adf-datatable-cell',
|
||||||
imports: [CommonModule, ClipboardDirective, TruncatePipe],
|
imports: [ClipboardDirective, TruncatePipe, AsyncPipe],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: `
|
template: `
|
||||||
@let value = value$ | async;
|
@let value = value$ | async;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { ContainerColumnModel } from './container-column.model';
|
|||||||
import { FormFieldTypes } from './form-field-types';
|
import { FormFieldTypes } from './form-field-types';
|
||||||
|
|
||||||
export class ContainerModel extends FormWidgetModel {
|
export class ContainerModel extends FormWidgetModel {
|
||||||
field: FormFieldModel;
|
declare field: FormFieldModel;
|
||||||
|
|
||||||
readonly columns: ContainerColumnModel[] = [];
|
readonly columns: ContainerColumnModel[] = [];
|
||||||
isExpanded: boolean = true;
|
isExpanded: boolean = true;
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
private readonly defaultEmptyOptionName = 'Choose one...';
|
private readonly defaultEmptyOptionName = 'Choose one...';
|
||||||
|
|
||||||
// model members
|
// model members
|
||||||
fieldType: string;
|
declare fieldType: string;
|
||||||
id: string;
|
declare id: string;
|
||||||
name: string;
|
declare name: string;
|
||||||
type: string;
|
declare type: string;
|
||||||
overrideId: boolean;
|
overrideId: boolean;
|
||||||
tab: string;
|
declare tab: string;
|
||||||
rowspan: number = 1;
|
rowspan: number = 1;
|
||||||
colspan: number = 1;
|
colspan: number = 1;
|
||||||
placeholder: string = null;
|
placeholder: string = null;
|
||||||
@@ -98,7 +98,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
variableConfig: VariableConfig;
|
variableConfig: VariableConfig;
|
||||||
schemaDefinition: DataColumn[];
|
schemaDefinition: DataColumn[];
|
||||||
externalProperty?: string;
|
externalProperty?: string;
|
||||||
style?: string;
|
declare style?: string;
|
||||||
parent?: RepeatableSectionModel;
|
parent?: RepeatableSectionModel;
|
||||||
|
|
||||||
// container model members
|
// container model members
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ export class TaskListCloudSortingModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TaskListRequestSortingModel extends TaskListCloudSortingModel {
|
export class TaskListRequestSortingModel extends TaskListCloudSortingModel {
|
||||||
orderBy: string;
|
declare orderBy: string;
|
||||||
direction: string;
|
declare direction: string;
|
||||||
|
|
||||||
isFieldProcessVariable: boolean;
|
isFieldProcessVariable: boolean;
|
||||||
processVariableData?: {
|
processVariableData?: {
|
||||||
processDefinitionKey: string;
|
processDefinitionKey: string;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(obj: TaskListRequestSortingModel) {
|
constructor(obj: TaskListRequestSortingModel) {
|
||||||
super(obj);
|
super(obj);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export const mockPreselectedFoodUsers = [
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class IdentityUserServiceMock extends IdentityUserService {
|
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 {
|
getCurrentUserInfo(): IdentityUserModel {
|
||||||
return mockKielbasaSausage;
|
return mockKielbasaSausage;
|
||||||
|
|||||||
+4
-4
@@ -18,7 +18,7 @@
|
|||||||
export class ProcessListCloudSortingModel {
|
export class ProcessListCloudSortingModel {
|
||||||
orderBy: string;
|
orderBy: string;
|
||||||
direction: string;
|
direction: string;
|
||||||
constructor(obj: any) {
|
constructor(obj: any) {
|
||||||
if (obj) {
|
if (obj) {
|
||||||
this.orderBy = obj.orderBy;
|
this.orderBy = obj.orderBy;
|
||||||
this.direction = obj.direction;
|
this.direction = obj.direction;
|
||||||
@@ -26,14 +26,14 @@ export class ProcessListCloudSortingModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class ProcessListRequestSortingModel extends ProcessListCloudSortingModel {
|
export class ProcessListRequestSortingModel extends ProcessListCloudSortingModel {
|
||||||
orderBy: string;
|
declare orderBy: string;
|
||||||
direction: string;
|
declare direction: string;
|
||||||
|
|
||||||
isFieldProcessVariable: boolean;
|
isFieldProcessVariable: boolean;
|
||||||
processVariableData?: {
|
processVariableData?: {
|
||||||
processDefinitionKey: string;
|
processDefinitionKey: string;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(obj: ProcessListRequestSortingModel) {
|
constructor(obj: ProcessListRequestSortingModel) {
|
||||||
super(obj);
|
super(obj);
|
||||||
|
|||||||
+1
-1
@@ -260,7 +260,7 @@ export class TaskListCloudComponent extends BaseTaskListCloudComponent<ProcessLi
|
|||||||
processVariableFilters: ProcessVariableFilterModel[];
|
processVariableFilters: ProcessVariableFilterModel[];
|
||||||
|
|
||||||
rows: TaskInstanceCloudListViewModel[] = [];
|
rows: TaskInstanceCloudListViewModel[] = [];
|
||||||
dataAdapter: TasksListDatatableAdapter | undefined;
|
declare dataAdapter: TasksListDatatableAdapter | undefined;
|
||||||
|
|
||||||
private isReloadingSubject$ = new BehaviorSubject<boolean>(false);
|
private isReloadingSubject$ = new BehaviorSubject<boolean>(false);
|
||||||
isLoading$ = combineLatest([this.isLoadingPreferences$, this.isReloadingSubject$]).pipe(
|
isLoading$ = combineLatest([this.isLoadingPreferences$, this.isReloadingSubject$]).pipe(
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
},
|
},
|
||||||
"tasksRunnerOptions": {
|
"tasksRunnerOptions": {
|
||||||
"default": {
|
"default": {
|
||||||
|
"runner": "nx/tasks-runners/default",
|
||||||
"options": {
|
"options": {
|
||||||
"runtimeCacheInputs": ["node -v"]
|
"runtimeCacheInputs": ["node -v"]
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
"version": "8.3.0",
|
"version": "8.3.0",
|
||||||
"author": "Hyland Software, Inc. and its affiliates",
|
"author": "Hyland Software, Inc. and its affiliates",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "husky install",
|
"prepare": "husky",
|
||||||
"bundle:js-api": "nx run js-api:bundle",
|
"bundle:js-api": "nx run js-api:bundle",
|
||||||
"bundle:cli": "nx run cli:bundle",
|
"bundle:cli": "nx run cli:bundle",
|
||||||
"test:affected": "nx affected:test",
|
"test:affected": "nx affected:test",
|
||||||
|
|||||||
Reference in New Issue
Block a user