Migrate to @angular-eslint/prefer-inject and @typescript-eslint/prefer-readonly (#11665)

This commit is contained in:
Denys Vuika
2026-02-18 15:38:01 +00:00
committed by GitHub
parent f8fa996b04
commit 3f542d99ba
470 changed files with 2638 additions and 2247 deletions
+2
View File
@@ -68,6 +68,7 @@ module.exports = {
], ],
'@angular-eslint/no-host-metadata-property': 'off', '@angular-eslint/no-host-metadata-property': 'off',
'@angular-eslint/no-input-prefix': 'error', '@angular-eslint/no-input-prefix': 'error',
'@angular-eslint/prefer-inject': 'error',
'@typescript-eslint/consistent-type-definitions': 'error', '@typescript-eslint/consistent-type-definitions': 'error',
'@typescript-eslint/dot-notation': 'off', '@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/explicit-member-accessibility': [ '@typescript-eslint/explicit-member-accessibility': [
@@ -78,6 +79,7 @@ module.exports = {
], ],
'@typescript-eslint/await-thenable': 'error', '@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/prefer-optional-chain': 'error', '@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/prefer-readonly': 'error',
'@typescript-eslint/no-inferrable-types': 'off', '@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-require-imports': 'off', '@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'error', '@typescript-eslint/no-var-requires': 'error',
+3
View File
@@ -11,6 +11,9 @@ const config: StorybookConfig = {
stories: ['lib/**/*.stories.ts'], stories: ['lib/**/*.stories.ts'],
features: { features: {
backgrounds: false backgrounds: false
},
core: {
disableTelemetry: true
} }
}; };
+3
View File
@@ -13,6 +13,9 @@ const config: StorybookConfig = {
framework: { framework: {
name: getAbsolutePath('@storybook/angular'), name: getAbsolutePath('@storybook/angular'),
options: {} options: {}
},
core: {
disableTelemetry: true
} }
}; };
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Agent, AgentsApi } from '@alfresco/js-api'; import { Agent, AgentsApi } from '@alfresco/js-api';
import { BehaviorSubject, from, Observable, of } from 'rxjs'; import { BehaviorSubject, from, Observable, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators'; import { map, switchMap } from 'rxjs/operators';
@@ -25,8 +25,10 @@ import { AlfrescoApiService } from '../../services';
providedIn: 'root' providedIn: 'root'
}) })
export class AgentService { export class AgentService {
private readonly apiService = inject(AlfrescoApiService);
private _agentsApi: AgentsApi; private _agentsApi: AgentsApi;
private agents = new BehaviorSubject<Agent[]>([]); private readonly agents = new BehaviorSubject<Agent[]>([]);
get agentsApi(): AgentsApi { get agentsApi(): AgentsApi {
this._agentsApi = this._agentsApi ?? new AgentsApi(this.apiService.getInstance()); this._agentsApi = this._agentsApi ?? new AgentsApi(this.apiService.getInstance());
@@ -35,8 +37,6 @@ export class AgentService {
agents$ = this.agents.asObservable(); agents$ = this.agents.asObservable();
constructor(private apiService: AlfrescoApiService) {}
/** /**
* Gets all agents from cache. If cache is empty, fetches agents from backend. * Gets all agents from cache. If cache is empty, fetches agents from backend.
* *
@@ -16,16 +16,13 @@
*/ */
import { AdfHttpClient } from '@alfresco/adf-core/api'; import { AdfHttpClient } from '@alfresco/adf-core/api';
import { StorageService, AppConfigService } from '@alfresco/adf-core';
import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api'; import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
@Injectable() @Injectable()
export class AlfrescoApiNoAuthService extends AlfrescoApiService { export class AlfrescoApiNoAuthService extends AlfrescoApiService {
constructor(storage: StorageService, appConfig: AppConfigService, private readonly adfHttpClient: AdfHttpClient) { private readonly adfHttpClient = inject(AdfHttpClient);
super(appConfig, storage);
}
override createInstance(config: AlfrescoApiConfig) { override createInstance(config: AlfrescoApiConfig) {
return new AlfrescoApi( return new AlfrescoApi(
@@ -16,7 +16,7 @@
*/ */
import { AlfrescoApiConfig } from '@alfresco/js-api'; import { AlfrescoApiConfig } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AppConfigService, AppConfigValues, StorageService } from '@alfresco/adf-core'; import { AppConfigService, AppConfigValues, StorageService } from '@alfresco/adf-core';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
import { SecurityOptionsLoaderService } from '../security-options-loader/security-options-loader.service'; import { SecurityOptionsLoaderService } from '../security-options-loader/security-options-loader.service';
@@ -35,12 +35,10 @@ export function createAlfrescoApiInstance(angularAlfrescoApiService: AlfrescoApi
providedIn: 'root' providedIn: 'root'
}) })
export class AlfrescoApiLoaderService { export class AlfrescoApiLoaderService {
constructor( private readonly appConfig = inject(AppConfigService);
private readonly appConfig: AppConfigService, private readonly apiService = inject(AlfrescoApiService);
private readonly apiService: AlfrescoApiService, private readonly securityOptionsLoaderService = inject(SecurityOptionsLoaderService);
private readonly securityOptionsLoaderService: SecurityOptionsLoaderService, private readonly storageService = inject(StorageService);
private storageService: StorageService
) {}
async init(): Promise<any> { async init(): Promise<any> {
await this.appConfig.load(this.securityOptionsLoaderService.load); await this.appConfig.load(this.securityOptionsLoaderService.load);
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { AspectListDialogComponentData } from './aspect-list-dialog-data.interface'; import { AspectListDialogComponentData } from './aspect-list-dialog-data.interface';
import { TranslatePipe } from '@ngx-translate/core'; import { TranslatePipe } from '@ngx-translate/core';
@@ -32,6 +32,9 @@ import { CommonModule } from '@angular/common';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AspectListDialogComponent implements OnInit { export class AspectListDialogComponent implements OnInit {
private readonly dialog = inject<MatDialogRef<AspectListDialogComponent>>(MatDialogRef);
data = inject<AspectListDialogComponentData>(MAT_DIALOG_DATA);
title: string; title: string;
description: string; description: string;
currentNodeId: string; currentNodeId: string;
@@ -40,7 +43,9 @@ export class AspectListDialogComponent implements OnInit {
currentAspectSelection: string[] = []; currentAspectSelection: string[] = [];
constructor(private dialog: MatDialogRef<AspectListDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: AspectListDialogComponentData) { constructor() {
const data = this.data;
this.title = data.title; this.title = data.title;
this.description = data.description; this.description = data.description;
this.overTableMessage = data.overTableMessage; this.overTableMessage = data.overTableMessage;
@@ -37,6 +37,9 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AspectListComponent implements OnInit { export class AspectListComponent implements OnInit {
private readonly aspectListService = inject(AspectListService);
private readonly nodeApiService = inject(NodesApiService);
/** Node Id of the node that we want to update */ /** Node Id of the node that we want to update */
@Input({ required: true }) @Input({ required: true })
nodeId: string = ''; nodeId: string = '';
@@ -67,8 +70,6 @@ export class AspectListComponent implements OnInit {
private standardAspectsLoaded = 0; private standardAspectsLoaded = 0;
private hasMoreAspects = false; private hasMoreAspects = false;
constructor(private aspectListService: AspectListService, private nodeApiService: NodesApiService) {}
ngOnInit(): void { ngOnInit(): void {
let aspects$: Observable<AspectEntry[]>; let aspects$: Observable<AspectEntry[]>;
if (this.nodeId) { if (this.nodeId) {
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { AppConfigService } from '@alfresco/adf-core'; import { AppConfigService } from '@alfresco/adf-core';
import { from, Observable, of, zip } from 'rxjs'; import { from, Observable, of, zip } from 'rxjs';
@@ -30,14 +30,15 @@ export const CustomAspectsWhere = `(not namespaceUri matches('http://www.alfresc
providedIn: 'root' providedIn: 'root'
}) })
export class AspectListService { export class AspectListService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly appConfigService = inject(AppConfigService);
private _aspectsApi: AspectsApi; private _aspectsApi: AspectsApi;
get aspectsApi(): AspectsApi { get aspectsApi(): AspectsApi {
this._aspectsApi = this._aspectsApi ?? new AspectsApi(this.alfrescoApiService.getInstance()); this._aspectsApi = this._aspectsApi ?? new AspectsApi(this.alfrescoApiService.getInstance());
return this._aspectsApi; return this._aspectsApi;
} }
constructor(private alfrescoApiService: AlfrescoApiService, private appConfigService: AppConfigService) {}
getAllAspects(standardOpts?: ListAspectsOpts, customOpts?: ListAspectsOpts): Observable<CustomAspectPaging> { getAllAspects(standardOpts?: ListAspectsOpts, customOpts?: ListAspectsOpts): Observable<CustomAspectPaging> {
const visibleAspectList = this.getVisibleAspects(); const visibleAspectList = this.getVisibleAspects();
const standardAspects$ = this.getAspects(visibleAspectList, standardOpts); const standardAspects$ = this.getAspects(visibleAspectList, standardOpts);
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { AspectListDialogComponentData } from '../aspect-list-dialog-data.interface'; import { AspectListDialogComponentData } from '../aspect-list-dialog-data.interface';
@@ -28,12 +28,10 @@ import { CategoryService } from '../../category';
providedIn: 'root' providedIn: 'root'
}) })
export class DialogAspectListService { export class DialogAspectListService {
constructor( private readonly dialog = inject(MatDialog);
private dialog: MatDialog, private readonly overlayContainer = inject(OverlayContainer);
private overlayContainer: OverlayContainer, private readonly tagService = inject(TagService);
private tagService: TagService, private readonly categoryService = inject(CategoryService);
private categoryService: CategoryService
) {}
openAspectListDialog(nodeId?: string, selectorAutoFocusedOnClose?: string): Observable<string[]> { openAspectListDialog(nodeId?: string, selectorAutoFocusedOnClose?: string): Observable<string[]> {
const select = new Subject<string[]>(); const select = new Subject<string[]>();
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { DialogAspectListService } from './dialog-aspect-list.service'; import { DialogAspectListService } from './dialog-aspect-list.service';
import { CardViewContentUpdateService } from '../../common/services/card-view-content-update.service'; import { CardViewContentUpdateService } from '../../common/services/card-view-content-update.service';
import { NodesApiService } from '../../common/services/nodes-api.service'; import { NodesApiService } from '../../common/services/nodes-api.service';
@@ -25,12 +25,10 @@ import { TagService } from '../../tag/services/tag.service';
providedIn: 'root' providedIn: 'root'
}) })
export class NodeAspectService { export class NodeAspectService {
constructor( private readonly nodesApiService = inject(NodesApiService);
private nodesApiService: NodesApiService, private readonly dialogAspectListService = inject(DialogAspectListService);
private dialogAspectListService: DialogAspectListService, private readonly cardViewContentUpdateService = inject(CardViewContentUpdateService);
private cardViewContentUpdateService: CardViewContentUpdateService, private readonly tagService = inject(TagService);
private tagService: TagService
) {}
updateNodeAspects(nodeId: string, selectorAutoFocusedOnClose?: string) { updateNodeAspects(nodeId: string, selectorAutoFocusedOnClose?: string) {
this.dialogAspectListService.openAspectListDialog(nodeId, selectorAutoFocusedOnClose).subscribe((aspectList) => { this.dialogAspectListService.openAspectListDialog(nodeId, selectorAutoFocusedOnClose).subscribe((aspectList) => {
@@ -15,13 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AuthenticationService, BasicAlfrescoAuthService } from '@alfresco/adf-core'; import { AuthenticationService, BasicAlfrescoAuthService } from '@alfresco/adf-core';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
@Injectable() @Injectable()
export class ContentAuthLoaderService { export class ContentAuthLoaderService {
constructor(private readonly basicAlfrescoAuthService: BasicAlfrescoAuthService, private readonly authService: AuthenticationService) {} private readonly basicAlfrescoAuthService = inject(BasicAlfrescoAuthService);
private readonly authService = inject(AuthenticationService);
init(): void { init(): void {
this.authService.onLogin.pipe(take(1)).subscribe({ this.authService.onLogin.pipe(take(1)).subscribe({
@@ -73,6 +73,8 @@ interface CategoryNameControlErrors {
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class CategoriesManagementComponent implements OnInit, OnDestroy { export class CategoriesManagementComponent implements OnInit, OnDestroy {
private readonly categoryService = inject(CategoryService);
readonly nameErrorMessagesByErrors = new Map<keyof CategoryNameControlErrors, string>([ readonly nameErrorMessagesByErrors = new Map<keyof CategoryNameControlErrors, string>([
['duplicatedExistingCategory', 'ALREADY_EXISTS'], ['duplicatedExistingCategory', 'ALREADY_EXISTS'],
['duplicatedCategory', 'DUPLICATED_CATEGORY'], ['duplicatedCategory', 'DUPLICATED_CATEGORY'],
@@ -82,9 +84,9 @@ export class CategoriesManagementComponent implements OnInit, OnDestroy {
['endsWithDot', 'ENDS_WITH_DOT'] ['endsWithDot', 'ENDS_WITH_DOT']
]); ]);
private existingCategoryLoaded$ = new Subject<void>(); private readonly existingCategoryLoaded$ = new Subject<void>();
private cancelExistingCategoriesLoading$ = new Subject<void>(); private readonly cancelExistingCategoriesLoading$ = new Subject<void>();
private _categoryNameControl = new FormControl<string>( private readonly _categoryNameControl = new FormControl<string>(
'', '',
[ [
this.validateIfNotAlreadyAdded.bind(this), this.validateIfNotAlreadyAdded.bind(this),
@@ -168,12 +170,10 @@ export class CategoriesManagementComponent implements OnInit, OnDestroy {
categoryNameControlVisibleChange = new EventEmitter<boolean>(); categoryNameControlVisibleChange = new EventEmitter<boolean>();
@ViewChild('categoryNameInput') @ViewChild('categoryNameInput')
private categoryNameInputElement: ElementRef; private readonly categoryNameInputElement: ElementRef;
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(private categoryService: CategoryService) {}
ngOnInit() { ngOnInit() {
this.categoryNameControl.valueChanges this.categoryNameControl.valueChanges
.pipe( .pipe(
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { TreeNodeType, TreeResponse, TreeService } from '../../tree'; import { TreeNodeType, TreeResponse, TreeService } from '../../tree';
import { CategoryNode } from '../models/category-node.interface'; import { CategoryNode } from '../models/category-node.interface';
import { CategoryService } from './category.service'; import { CategoryService } from './category.service';
@@ -24,9 +24,7 @@ import { map, mergeMap, toArray } from 'rxjs/operators';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class CategoryTreeDatasourceService extends TreeService<CategoryNode> { export class CategoryTreeDatasourceService extends TreeService<CategoryNode> {
constructor(private categoryService: CategoryService) { private readonly categoryService = inject(CategoryService);
super();
}
public getSubNodes(parentNodeId: string, skipCount?: number, maxItems?: number, name?: string): Observable<TreeResponse<CategoryNode>> { public getSubNodes(parentNodeId: string, skipCount?: number, maxItems?: number, name?: string): Observable<TreeResponse<CategoryNode>> {
return !name return !name
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core'; import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core';
import { import {
CategoriesApi, CategoriesApi,
@@ -32,6 +32,10 @@ import { from, Observable } from 'rxjs';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class CategoryService { export class CategoryService {
private readonly apiService = inject(AlfrescoApiService);
private readonly userPreferencesService = inject(UserPreferencesService);
private readonly appConfigService = inject(AppConfigService);
private _categoriesApi: CategoriesApi; private _categoriesApi: CategoriesApi;
private _searchApi: SearchApi; private _searchApi: SearchApi;
@@ -45,12 +49,6 @@ export class CategoryService {
return this._searchApi; return this._searchApi;
} }
constructor(
private apiService: AlfrescoApiService,
private userPreferencesService: UserPreferencesService,
private appConfigService: AppConfigService
) {}
/** /**
* Get subcategories of a given parent category * Get subcategories of a given parent category
* *
@@ -17,17 +17,19 @@
import { UpdateNotification, CardViewBaseItemModel, CardViewUpdateService } from '@alfresco/adf-core'; import { UpdateNotification, CardViewBaseItemModel, CardViewUpdateService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class CardViewContentUpdateService { export class CardViewContentUpdateService {
private readonly cardViewUpdateService = inject(CardViewUpdateService);
itemUpdated$ = new Subject<UpdateNotification>(); itemUpdated$ = new Subject<UpdateNotification>();
updatedAspect$ = new Subject<Node>(); updatedAspect$ = new Subject<Node>();
constructor(private cardViewUpdateService: CardViewUpdateService) { constructor() {
this.linkVariables(); this.linkVariables();
} }
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { ContentApi, Node, NodeEntry } from '@alfresco/js-api'; import { ContentApi, Node, NodeEntry } from '@alfresco/js-api';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { AuthenticationService, ThumbnailService } from '@alfresco/adf-core'; import { AuthenticationService, ThumbnailService } from '@alfresco/adf-core';
@@ -34,6 +34,10 @@ export interface FolderCreatedEvent {
providedIn: 'root' providedIn: 'root'
}) })
export class ContentService { export class ContentService {
authService = inject(AuthenticationService);
apiService = inject(AlfrescoApiService);
private readonly thumbnailService = inject(ThumbnailService);
folderCreated = new Subject<FolderCreatedEvent>(); folderCreated = new Subject<FolderCreatedEvent>();
folderCreate = new Subject<Node>(); folderCreate = new Subject<Node>();
folderEdit = new Subject<Node>(); folderEdit = new Subject<Node>();
@@ -44,8 +48,6 @@ export class ContentService {
return this._contentApi; return this._contentApi;
} }
constructor(public authService: AuthenticationService, public apiService: AlfrescoApiService, private thumbnailService?: ThumbnailService) {}
/** /**
* Gets a content URL for the given node. * Gets a content URL for the given node.
* *
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { from, Observable, throwError, Subject } from 'rxjs'; import { from, Observable, throwError, Subject } from 'rxjs';
import { catchError, map, switchMap, filter, take } from 'rxjs/operators'; import { catchError, map, switchMap, filter, take } from 'rxjs/operators';
import { RepositoryInfo, SystemPropertiesRepresentation, DiscoveryApi, AboutApi, SystemPropertiesApi } from '@alfresco/js-api'; import { RepositoryInfo, SystemPropertiesRepresentation, DiscoveryApi, AboutApi, SystemPropertiesApi } from '@alfresco/js-api';
@@ -27,6 +27,9 @@ import { BpmProductVersionModel, AuthenticationService } from '@alfresco/adf-cor
providedIn: 'root' providedIn: 'root'
}) })
export class DiscoveryApiService { export class DiscoveryApiService {
private readonly authenticationService = inject(AuthenticationService);
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _discoveryApi: DiscoveryApi; private _discoveryApi: DiscoveryApi;
get discoveryApi(): DiscoveryApi { get discoveryApi(): DiscoveryApi {
this._discoveryApi = this._discoveryApi ?? new DiscoveryApi(this.alfrescoApiService.getInstance()); this._discoveryApi = this._discoveryApi ?? new DiscoveryApi(this.alfrescoApiService.getInstance());
@@ -38,10 +41,7 @@ export class DiscoveryApiService {
*/ */
ecmProductInfo$ = new Subject<RepositoryInfo>(); ecmProductInfo$ = new Subject<RepositoryInfo>();
constructor( constructor() {
private readonly authenticationService: AuthenticationService,
private readonly alfrescoApiService: AlfrescoApiService
) {
this.authenticationService.onLogin.subscribe(() => { this.authenticationService.onLogin.subscribe(() => {
this.alfrescoApiService.alfrescoApiInitialized this.alfrescoApiService.alfrescoApiInitialized
.pipe( .pipe(
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { FavoritesApi, NodePaging, FavoritePaging } from '@alfresco/js-api'; import { FavoritesApi, NodePaging, FavoritePaging } from '@alfresco/js-api';
import { Observable, from, of } from 'rxjs'; import { Observable, from, of } from 'rxjs';
import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -26,6 +26,9 @@ import { catchError } from 'rxjs/operators';
providedIn: 'root' providedIn: 'root'
}) })
export class FavoritesApiService { export class FavoritesApiService {
private readonly apiService = inject(AlfrescoApiService);
private readonly preferences = inject(UserPreferencesService);
private _favoritesApi: FavoritesApi; private _favoritesApi: FavoritesApi;
get favoritesApi(): FavoritesApi { get favoritesApi(): FavoritesApi {
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.apiService.getInstance()); this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.apiService.getInstance());
@@ -41,8 +44,6 @@ export class FavoritesApiService {
return { entry }; return { entry };
} }
constructor(private apiService: AlfrescoApiService, private preferences: UserPreferencesService) {}
remapFavoritesData(data: FavoritePaging = {}): NodePaging { remapFavoritesData(data: FavoritePaging = {}): NodePaging {
const pagination = data?.list?.pagination || {}; const pagination = data?.list?.pagination || {};
const entries: any[] = this.remapFavoriteEntries(data?.list?.entries || []); const entries: any[] = this.remapFavoriteEntries(data?.list?.entries || []);
@@ -29,7 +29,7 @@ import {
JobIdBodyEntry, JobIdBodyEntry,
NodeAssociationPaging NodeAssociationPaging
} from '@alfresco/js-api'; } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { from, Observable, Subject, throwError } from 'rxjs'; import { from, Observable, Subject, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators'; import { catchError, map } from 'rxjs/operators';
import { NodeMetadata } from '../models/node-metadata.model'; import { NodeMetadata } from '../models/node-metadata.model';
@@ -39,6 +39,9 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
providedIn: 'root' providedIn: 'root'
}) })
export class NodesApiService { export class NodesApiService {
private readonly apiService = inject(AlfrescoApiService);
private readonly preferences = inject(UserPreferencesService);
/** /**
* Publish/subscribe to events related to node updates. * Publish/subscribe to events related to node updates.
*/ */
@@ -56,11 +59,6 @@ export class NodesApiService {
return this._nodesApi; return this._nodesApi;
} }
constructor(
private readonly apiService: AlfrescoApiService,
private readonly preferences: UserPreferencesService
) {}
private getEntryFromEntity(entity: NodeEntry): Node { private getEntryFromEntity(entity: NodeEntry): Node {
return entity.entry; return entity.entry;
} }
@@ -20,7 +20,8 @@ import { RedirectAuthService } from '@alfresco/adf-core';
import { PeopleContentQueryRequestModel, PeopleContentService } from './people-content.service'; import { PeopleContentQueryRequestModel, PeopleContentService } from './people-content.service';
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { PersonPaging } from '@alfresco/js-api'; import { PersonPaging } from '@alfresco/js-api';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { EMPTY, firstValueFrom, of } from 'rxjs'; import { EMPTY, firstValueFrom, of } from 'rxjs';
import { AlfrescoApiService } from '../../services'; import { AlfrescoApiService } from '../../services';
import { AlfrescoApiServiceMock } from '../../mock'; import { AlfrescoApiServiceMock } from '../../mock';
@@ -70,11 +71,12 @@ describe('PeopleContentService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ providers: [
PeopleContentService, PeopleContentService,
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
{ provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } } { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } },
provideHttpClient(),
provideHttpClientTesting()
] ]
}); });
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { from, Observable, of } from 'rxjs'; import { from, Observable, of } from 'rxjs';
import { AuthenticationService } from '@alfresco/adf-core'; import { AuthenticationService } from '@alfresco/adf-core';
import { map, tap } from 'rxjs/operators'; import { map, tap } from 'rxjs/operators';
@@ -44,6 +44,9 @@ export interface PeopleContentQueryRequestModel {
providedIn: 'root' providedIn: 'root'
}) })
export class PeopleContentService { export class PeopleContentService {
private readonly apiService = inject(AlfrescoApiService);
private readonly contentService = inject(ContentService);
private currentUser: EcmUserModel; private currentUser: EcmUserModel;
private _peopleApi: PeopleApi; private _peopleApi: PeopleApi;
@@ -52,7 +55,9 @@ export class PeopleContentService {
return this._peopleApi; return this._peopleApi;
} }
constructor(private apiService: AlfrescoApiService, authenticationService: AuthenticationService, private contentService: ContentService) { constructor() {
const authenticationService = inject(AuthenticationService);
authenticationService.onLogout.subscribe(() => { authenticationService.onLogout.subscribe(() => {
this.resetLocalCurrentUser(); this.resetLocalCurrentUser();
}); });
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { ContentApi, RenditionEntry, RenditionPaging, RenditionsApi, VersionsApi } from '@alfresco/js-api'; import { ContentApi, RenditionEntry, RenditionPaging, RenditionsApi, VersionsApi } from '@alfresco/js-api';
import { Track, TranslationService, ViewUtilService } from '@alfresco/adf-core'; import { Track, TranslationService, ViewUtilService } from '@alfresco/adf-core';
import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -24,6 +24,10 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
providedIn: 'root' providedIn: 'root'
}) })
export class RenditionService { export class RenditionService {
private readonly apiService = inject(AlfrescoApiService);
private readonly translateService = inject(TranslationService);
private readonly viewUtilsService = inject(ViewUtilService);
static TARGET = '_new'; static TARGET = '_new';
/** /**
@@ -51,7 +55,7 @@ export class RenditionService {
/** /**
* Timeout used for setInterval. * Timeout used for setInterval.
*/ */
private TRY_TIMEOUT: number = 10000; private readonly TRY_TIMEOUT: number = 10000;
_renditionsApi: RenditionsApi; _renditionsApi: RenditionsApi;
get renditionsApi(): RenditionsApi { get renditionsApi(): RenditionsApi {
@@ -66,19 +70,13 @@ export class RenditionService {
} }
_versionsApi: VersionsApi; _versionsApi: VersionsApi;
private DEFAULT_RENDITION: string = 'imgpreview'; private readonly DEFAULT_RENDITION: string = 'imgpreview';
get versionsApi(): VersionsApi { get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance()); this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
return this._versionsApi; return this._versionsApi;
} }
constructor(
private readonly apiService: AlfrescoApiService,
private readonly translateService: TranslationService,
private readonly viewUtilsService: ViewUtilService
) {}
getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string { getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string {
return renditionExists && type !== RenditionService.ContentGroup.IMAGE return renditionExists && type !== RenditionService.ContentGroup.IMAGE
? this.contentApi.getRenditionUrl(nodeId, RenditionService.ContentGroup.PDF) ? this.contentApi.getRenditionUrl(nodeId, RenditionService.ContentGroup.PDF)
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { inject, Injectable } from '@angular/core';
import { SavedSearchStrategy } from '../interfaces/saved-searches-strategy.interface'; import { SavedSearchStrategy } from '../interfaces/saved-searches-strategy.interface';
import { AuthenticationService } from '@alfresco/adf-core'; import { AuthenticationService } from '@alfresco/adf-core';
import { ReplaySubject, Observable, catchError, switchMap, take, tap, throwError, map } from 'rxjs'; import { ReplaySubject, Observable, catchError, switchMap, take, tap, throwError, map } from 'rxjs';
@@ -32,16 +32,14 @@ export abstract class SavedSearchesBaseService implements SavedSearchStrategy {
protected readonly _savedSearches$ = new ReplaySubject<SavedSearch[]>(1); protected readonly _savedSearches$ = new ReplaySubject<SavedSearch[]>(1);
readonly savedSearches$: Observable<SavedSearch[]> = this._savedSearches$.asObservable(); readonly savedSearches$: Observable<SavedSearch[]> = this._savedSearches$.asObservable();
protected readonly apiService = inject(AlfrescoApiService);
protected readonly authService = inject(AuthenticationService);
get nodesApi(): NodesApi { get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance()); this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi; return this._nodesApi;
} }
protected constructor(
protected readonly apiService: AlfrescoApiService,
protected readonly authService: AuthenticationService
) {}
protected abstract fetchAllSavedSearches(): Observable<SavedSearch[]>; protected abstract fetchAllSavedSearches(): Observable<SavedSearch[]>;
protected abstract updateSavedSearches(searches: SavedSearch[]): Observable<NodeEntry>; protected abstract updateSavedSearches(searches: SavedSearch[]): Observable<NodeEntry>;
@@ -19,9 +19,7 @@ import { NodeEntry } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, of, from, throwError } from 'rxjs'; import { Observable, of, from, throwError } from 'rxjs';
import { catchError, concatMap, first, map } from 'rxjs/operators'; import { catchError, concatMap, first, map } from 'rxjs/operators';
import { AlfrescoApiService } from '../../services';
import { SavedSearch } from '../interfaces/saved-search.interface'; import { SavedSearch } from '../interfaces/saved-search.interface';
import { AuthenticationService } from '@alfresco/adf-core';
import { SavedSearchesBaseService } from './saved-searches-base.service'; import { SavedSearchesBaseService } from './saved-searches-base.service';
@Injectable({ @Injectable({
@@ -32,10 +30,6 @@ export class SavedSearchesLegacyService extends SavedSearchesBaseService {
private currentUserLocalStorageKey: string; private currentUserLocalStorageKey: string;
private createFileAttempt = false; private createFileAttempt = false;
constructor(apiService: AlfrescoApiService, authService: AuthenticationService) {
super(apiService, authService);
}
protected fetchAllSavedSearches(): Observable<SavedSearch[]> { protected fetchAllSavedSearches(): Observable<SavedSearch[]> {
return this.getSavedSearchesNodeId().pipe( return this.getSavedSearchesNodeId().pipe(
concatMap(() => concatMap(() =>
@@ -16,12 +16,10 @@
*/ */
import { NodeEntry, PreferencesApi, ContentFieldsQuery, PreferenceEntry } from '@alfresco/js-api'; import { NodeEntry, PreferencesApi, ContentFieldsQuery, PreferenceEntry } from '@alfresco/js-api';
import { inject, Injectable, InjectionToken } from '@angular/core'; import { Injectable, InjectionToken, inject } from '@angular/core';
import { Observable, of, from, throwError } from 'rxjs'; import { Observable, of, from, throwError } from 'rxjs';
import { catchError, concatMap, first, map, switchMap, take, tap } from 'rxjs/operators'; import { catchError, concatMap, first, map, switchMap, take, tap } from 'rxjs/operators';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { SavedSearch } from '../interfaces/saved-search.interface'; import { SavedSearch } from '../interfaces/saved-search.interface';
import { AuthenticationService } from '@alfresco/adf-core';
import { SavedSearchesBaseService } from './saved-searches-base.service'; import { SavedSearchesBaseService } from './saved-searches-base.service';
export interface SavedSearchesPreferencesApiService { export interface SavedSearchesPreferencesApiService {
@@ -37,7 +35,7 @@ export const SAVED_SEARCHES_SERVICE_PREFERENCES = new InjectionToken<SavedSearch
export class SavedSearchesService extends SavedSearchesBaseService { export class SavedSearchesService extends SavedSearchesBaseService {
private savedSearchFileNodeId: string; private savedSearchFileNodeId: string;
private _preferencesApi: SavedSearchesPreferencesApiService; private _preferencesApi: SavedSearchesPreferencesApiService;
private preferencesService = inject(SAVED_SEARCHES_SERVICE_PREFERENCES, { optional: true }); private readonly preferencesService = inject(SAVED_SEARCHES_SERVICE_PREFERENCES, { optional: true });
get preferencesApi(): SavedSearchesPreferencesApiService { get preferencesApi(): SavedSearchesPreferencesApiService {
if (this.preferencesService) { if (this.preferencesService) {
@@ -49,10 +47,6 @@ export class SavedSearchesService extends SavedSearchesBaseService {
return this._preferencesApi; return this._preferencesApi;
} }
constructor(apiService: AlfrescoApiService, authService: AuthenticationService) {
super(apiService, authService);
}
protected fetchAllSavedSearches(): Observable<SavedSearch[]> { protected fetchAllSavedSearches(): Observable<SavedSearch[]> {
const savedSearchesMigrated = localStorage.getItem(this.getLocalStorageKey()) ?? ''; const savedSearchesMigrated = localStorage.getItem(this.getLocalStorageKey()) ?? '';
if (savedSearchesMigrated === 'true') { if (savedSearchesMigrated === 'true') {
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
import { import {
Node, Node,
@@ -37,14 +37,14 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
providedIn: 'root' providedIn: 'root'
}) })
export class SitesService { export class SitesService {
private readonly apiService = inject(AlfrescoApiService);
private _sitesApi: SitesApi; private _sitesApi: SitesApi;
get sitesApi(): SitesApi { get sitesApi(): SitesApi {
this._sitesApi = this._sitesApi ?? new SitesApi(this.apiService.getInstance()); this._sitesApi = this._sitesApi ?? new SitesApi(this.apiService.getInstance());
return this._sitesApi; return this._sitesApi;
} }
constructor(private apiService: AlfrescoApiService) {}
/** /**
* Create a site * Create a site
* *
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation, inject } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { NodeAspectService } from '../../../aspect-list/services/node-aspect.service'; import { NodeAspectService } from '../../../aspect-list/services/node-aspect.service';
import { ContentMetadataCustomPanel, PresetConfig } from '../../interfaces/content-metadata.interfaces'; import { ContentMetadataCustomPanel, PresetConfig } from '../../interfaces/content-metadata.interfaces';
@@ -38,6 +38,10 @@ import { IconModule } from '@alfresco/adf-core';
host: { class: 'adf-content-metadata-card' } host: { class: 'adf-content-metadata-card' }
}) })
export class ContentMetadataCardComponent implements OnChanges { export class ContentMetadataCardComponent implements OnChanges {
private readonly contentService = inject(ContentService);
private readonly nodeAspectService = inject(NodeAspectService);
private readonly versionCompatibilityService = inject(VersionCompatibilityService);
/** (required) The node entity to fetch metadata about */ /** (required) The node entity to fetch metadata about */
@Input({ required: true }) @Input({ required: true })
node: Node; node: Node;
@@ -110,11 +114,7 @@ export class ContentMetadataCardComponent implements OnChanges {
editAspectSupported = false; editAspectSupported = false;
constructor( constructor() {
private contentService: ContentService,
private nodeAspectService: NodeAspectService,
private versionCompatibilityService: VersionCompatibilityService
) {
this.editAspectSupported = this.versionCompatibilityService.isVersionSupported('7'); this.editAspectSupported = this.versionCompatibilityService.isVersionSupported('7');
} }
@@ -86,6 +86,16 @@ export type DefaultPanels = (typeof DefaultPanels)[keyof typeof DefaultPanels];
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ContentMetadataComponent implements OnChanges, OnInit { export class ContentMetadataComponent implements OnChanges, OnInit {
private readonly contentMetadataService = inject(ContentMetadataService);
private readonly cardViewContentUpdateService = inject(CardViewContentUpdateService);
private readonly nodesApiService = inject(NodesApiService);
private readonly translationService = inject(TranslationService);
private readonly appConfig = inject(AppConfigService);
private readonly tagService = inject(TagService);
private readonly categoryService = inject(CategoryService);
private readonly contentService = inject(ContentService);
private readonly notificationService = inject(NotificationService);
/** (required) The node entity to fetch metadata about */ /** (required) The node entity to fetch metadata about */
@Input({ required: true }) @Input({ required: true })
node: Node; node: Node;
@@ -146,10 +156,10 @@ export class ContentMetadataComponent implements OnChanges, OnInit {
private _assignedTags: string[] = []; private _assignedTags: string[] = [];
private assignedTagsEntries: TagEntry[] = []; private assignedTagsEntries: TagEntry[] = [];
private _tagsCreatorMode = TagsCreatorMode.CREATE_AND_ASSIGN; private readonly _tagsCreatorMode = TagsCreatorMode.CREATE_AND_ASSIGN;
private _tags: string[] = []; private _tags: string[] = [];
private targetProperty: CardViewBaseItemModel; private targetProperty: CardViewBaseItemModel;
private classifiableChangedSubject = new Subject<void>(); private readonly classifiableChangedSubject = new Subject<void>();
private _saving = false; private _saving = false;
DefaultPanels = DefaultPanels; DefaultPanels = DefaultPanels;
@@ -174,17 +184,7 @@ export class ContentMetadataComponent implements OnChanges, OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor( constructor() {
private contentMetadataService: ContentMetadataService,
private cardViewContentUpdateService: CardViewContentUpdateService,
private nodesApiService: NodesApiService,
private translationService: TranslationService,
private appConfig: AppConfigService,
private tagService: TagService,
private categoryService: CategoryService,
private contentService: ContentService,
private notificationService: NotificationService
) {
this.copyToClipboardAction = this.appConfig.get<boolean>('content-metadata.copy-to-clipboard-action'); this.copyToClipboardAction = this.appConfig.get<boolean>('content-metadata.copy-to-clipboard-action');
this.multiValueSeparator = this.appConfig.get<string>('content-metadata.multi-value-pipe-separator') || DEFAULT_SEPARATOR; this.multiValueSeparator = this.appConfig.get<string>('content-metadata.multi-value-pipe-separator') || DEFAULT_SEPARATOR;
this.useChipsForMultiValueProperty = this.appConfig.get<boolean>('content-metadata.multi-value-chips'); this.useChipsForMultiValueProperty = this.appConfig.get<boolean>('content-metadata.multi-value-chips');
@@ -15,15 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
import { inject, Injectable } from '@angular/core'; import { inject, Injectable, Injector, runInInjectionContext } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { CardViewDateItemModel, CardViewItemMatchValidator, CardViewTextItemModel, FileSizePipe, TranslationService } from '@alfresco/adf-core'; import { CardViewDateItemModel, CardViewItemMatchValidator, CardViewTextItemModel, FileSizePipe } from '@alfresco/adf-core';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class BasicPropertiesService { export class BasicPropertiesService {
private translationService = inject(TranslationService); private readonly injector = inject(Injector);
getProperties(node: Node) { getProperties(node: Node) {
const sizeInBytes = node.content ? node.content.sizeInBytes : ''; const sizeInBytes = node.content ? node.content.sizeInBytes : '';
@@ -63,7 +63,7 @@ export class BasicPropertiesService {
label: 'CORE.METADATA.BASIC.SIZE', label: 'CORE.METADATA.BASIC.SIZE',
value: sizeInBytes, value: sizeInBytes,
key: 'content.sizeInBytes', key: 'content.sizeInBytes',
pipes: [{ pipe: new FileSizePipe(this.translationService) }], pipes: [{ pipe: runInInjectionContext(this.injector, () => new FileSizePipe()) }],
editable: false editable: false
}), }),
new CardViewTextItemModel({ new CardViewTextItemModel({
@@ -19,7 +19,7 @@ import { ContentMetadataConfig, OrganisedPropertyGroup, PropertyGroupContainer,
import { getGroup, getProperty } from './property-group-reader'; import { getGroup, getProperty } from './property-group-reader';
export class AspectOrientedConfigService implements ContentMetadataConfig { export class AspectOrientedConfigService implements ContentMetadataConfig {
constructor(private config: any) {} constructor(private readonly config: any) {}
public isGroupAllowed(groupName: string): boolean { public isGroupAllowed(groupName: string): boolean {
if (this.isIncludeAllEnabled()) { if (this.isIncludeAllEnabled()) {
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AppConfigService, LogService } from '@alfresco/adf-core'; import { AppConfigService, LogService } from '@alfresco/adf-core';
import { AspectOrientedConfigService } from './aspect-oriented-config.service'; import { AspectOrientedConfigService } from './aspect-oriented-config.service';
import { IndifferentConfigService } from './indifferent-config.service'; import { IndifferentConfigService } from './indifferent-config.service';
@@ -29,7 +29,8 @@ const DEFAULT_PRESET_NAME = 'default';
providedIn: 'root' providedIn: 'root'
}) })
export class ContentMetadataConfigFactory { export class ContentMetadataConfigFactory {
constructor(private appConfigService: AppConfigService, private logService: LogService) {} private readonly appConfigService = inject(AppConfigService);
private readonly logService = inject(LogService);
public get(presetName: string = 'default'): ContentMetadataConfig { public get(presetName: string = 'default'): ContentMetadataConfig {
let presetConfig: PresetConfig; let presetConfig: PresetConfig;
@@ -25,7 +25,7 @@ import {
import { getProperty } from './property-group-reader'; import { getProperty } from './property-group-reader';
export class LayoutOrientedConfigService implements ContentMetadataConfig { export class LayoutOrientedConfigService implements ContentMetadataConfig {
constructor(private config: any) {} constructor(private readonly config: any) {}
public isGroupAllowed(groupName: string): boolean { public isGroupAllowed(groupName: string): boolean {
if (this.isIncludeAllEnabled()) { if (this.isIncludeAllEnabled()) {
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { BasicPropertiesService } from './basic-properties.service'; import { BasicPropertiesService } from './basic-properties.service';
import { Observable, of, iif, Subject } from 'rxjs'; import { Observable, of, iif, Subject } from 'rxjs';
@@ -30,15 +30,13 @@ import { ContentTypePropertiesService } from './content-type-property.service';
providedIn: 'root' providedIn: 'root'
}) })
export class ContentMetadataService { export class ContentMetadataService {
error = new Subject<{ statusCode: number; message: string }>(); private readonly basicPropertiesService = inject(BasicPropertiesService);
private readonly contentMetadataConfigFactory = inject(ContentMetadataConfigFactory);
private readonly propertyGroupTranslatorService = inject(PropertyGroupTranslatorService);
private readonly propertyDescriptorsService = inject(PropertyDescriptorsService);
private readonly contentTypePropertyService = inject(ContentTypePropertiesService);
constructor( error = new Subject<{ statusCode: number; message: string }>();
private basicPropertiesService: BasicPropertiesService,
private contentMetadataConfigFactory: ContentMetadataConfigFactory,
private propertyGroupTranslatorService: PropertyGroupTranslatorService,
private propertyDescriptorsService: PropertyDescriptorsService,
private contentTypePropertyService: ContentTypePropertiesService
) {}
getBasicProperties(node: Node): Observable<CardViewItem[]> { getBasicProperties(node: Node): Observable<CardViewItem[]> {
return of(this.basicPropertiesService.getProperties(node)); return of(this.basicPropertiesService.getProperties(node));
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { CardViewItem, CardViewSelectItemModel, CardViewSelectItemOption, CardViewTextItemModel } from '@alfresco/adf-core'; import { CardViewItem, CardViewSelectItemModel, CardViewSelectItemOption, CardViewTextItemModel } from '@alfresco/adf-core';
import { Observable, of, Subject, zip } from 'rxjs'; import { Observable, of, Subject, zip } from 'rxjs';
@@ -31,12 +31,10 @@ import { VersionCompatibilityService } from '../../version-compatibility/version
providedIn: 'root' providedIn: 'root'
}) })
export class ContentTypePropertiesService { export class ContentTypePropertiesService {
constructor( private readonly contentTypeService = inject(ContentTypeService);
private contentTypeService: ContentTypeService, private readonly dialog = inject(MatDialog);
private dialog: MatDialog, private readonly versionCompatibilityService = inject(VersionCompatibilityService);
private versionCompatibilityService: VersionCompatibilityService, private readonly propertyGroupTranslatorService = inject(PropertyGroupTranslatorService);
private propertyGroupTranslatorService: PropertyGroupTranslatorService
) {}
getContentTypeCardItem(node: Node): Observable<CardViewItem[]> { getContentTypeCardItem(node: Node): Observable<CardViewItem[]> {
if (this.versionCompatibilityService.isVersionSupported('7')) { if (this.versionCompatibilityService.isVersionSupported('7')) {
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { Observable, defer, forkJoin } from 'rxjs'; import { Observable, defer, forkJoin } from 'rxjs';
import { PropertyGroup, PropertyGroupContainer } from '../interfaces/content-metadata.interfaces'; import { PropertyGroup, PropertyGroupContainer } from '../interfaces/content-metadata.interfaces';
@@ -26,14 +26,14 @@ import { ClassesApi } from '@alfresco/js-api';
providedIn: 'root' providedIn: 'root'
}) })
export class PropertyDescriptorsService { export class PropertyDescriptorsService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _classesApi: ClassesApi; private _classesApi: ClassesApi;
get classesApi(): ClassesApi { get classesApi(): ClassesApi {
this._classesApi = this._classesApi ?? new ClassesApi(this.alfrescoApiService.getInstance()); this._classesApi = this._classesApi ?? new ClassesApi(this.alfrescoApiService.getInstance());
return this._classesApi; return this._classesApi;
} }
constructor(private alfrescoApiService: AlfrescoApiService) {}
load(groupNames: string[]): Observable<PropertyGroupContainer> { load(groupNames: string[]): Observable<PropertyGroupContainer> {
const groupFetchStreams = groupNames const groupFetchStreams = groupNames
.map((groupName) => groupName.replace(':', '_')) .map((groupName) => groupName.replace(':', '_'))
@@ -29,8 +29,7 @@ import {
CardViewSelectItemModel, CardViewSelectItemModel,
CardViewTextItemModel, CardViewTextItemModel,
DecimalNumberPipe, DecimalNumberPipe,
LogService, LogService
UserPreferencesService
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { CardViewGroup, OrganisedPropertyGroup, Property } from '../interfaces/content-metadata.interfaces'; import { CardViewGroup, OrganisedPropertyGroup, Property } from '../interfaces/content-metadata.interfaces';
import { of } from 'rxjs'; import { of } from 'rxjs';
@@ -53,9 +52,8 @@ export const RECOGNISED_ECM_TYPES = [D_TEXT, D_MLTEXT, D_DATE, D_DATETIME, D_INT
providedIn: 'root' providedIn: 'root'
}) })
export class PropertyGroupTranslatorService { export class PropertyGroupTranslatorService {
private userPreferenceService = inject(UserPreferencesService); private readonly appConfig = inject(AppConfigService);
private appConfig = inject(AppConfigService); private readonly logService = inject(LogService);
private logService = inject(LogService);
valueSeparator: string; valueSeparator: string;
@@ -221,7 +219,7 @@ export class PropertyGroupTranslatorService {
private getDecimalNumberPipe(): DecimalNumberPipe { private getDecimalNumberPipe(): DecimalNumberPipe {
let decimalNumberPipe: DecimalNumberPipe; let decimalNumberPipe: DecimalNumberPipe;
runInInjectionContext(this.injector, () => { runInInjectionContext(this.injector, () => {
decimalNumberPipe = new DecimalNumberPipe(this.userPreferenceService, this.appConfig); decimalNumberPipe = new DecimalNumberPipe();
}); });
return decimalNumberPipe; return decimalNumberPipe;
} }
@@ -16,7 +16,7 @@
*/ */
import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { EventEmitter, Injectable, Output } from '@angular/core'; import { EventEmitter, Injectable, Output, inject } from '@angular/core';
import { ThumbnailService, TranslationService } from '@alfresco/adf-core'; import { ThumbnailService, TranslationService } from '@alfresco/adf-core';
import { Subject, Observable, throwError } from 'rxjs'; import { Subject, Observable, throwError } from 'rxjs';
import { ShareDataRow } from '../document-list/data/share-data-row.model'; import { ShareDataRow } from '../document-list/data/share-data-row.model';
@@ -36,21 +36,19 @@ import { SitesService } from '../common/services/sites.service';
}) })
// eslint-disable-next-line @angular-eslint/directive-class-suffix // eslint-disable-next-line @angular-eslint/directive-class-suffix
export class ContentNodeDialogService { export class ContentNodeDialogService {
private readonly dialog = inject(MatDialog);
private readonly contentService = inject(ContentService);
private readonly documentListService = inject(DocumentListService);
private readonly siteService = inject(SitesService);
private readonly translation = inject(TranslationService);
private readonly thumbnailService = inject(ThumbnailService);
static nonDocumentSiteContent = ['blog', 'calendar', 'dataLists', 'discussions', 'links', 'wiki']; static nonDocumentSiteContent = ['blog', 'calendar', 'dataLists', 'discussions', 'links', 'wiki'];
/** Emitted when an error occurs. */ /** Emitted when an error occurs. */
@Output() @Output()
error: EventEmitter<any> = new EventEmitter<any>(); error: EventEmitter<any> = new EventEmitter<any>();
constructor(
private dialog: MatDialog,
private contentService: ContentService,
private documentListService: DocumentListService,
private siteService: SitesService,
private translation: TranslationService,
private thumbnailService: ThumbnailService
) {}
/** /**
* Opens a file browser at a chosen folder location. * Opens a file browser at a chosen folder location.
* shows files and folders in the dialog search result. * shows files and folders in the dialog search result.
@@ -90,6 +90,14 @@ export const defaultValidation = () => true;
providers: [SearchQueryBuilderService] providers: [SearchQueryBuilderService]
}) })
export class ContentNodeSelectorPanelComponent implements OnInit { export class ContentNodeSelectorPanelComponent implements OnInit {
private readonly customResourcesService = inject(CustomResourcesService);
private readonly queryBuilderService = inject(SearchQueryBuilderService);
private readonly userPreferencesService = inject(UserPreferencesService);
private readonly nodesApiService = inject(NodesApiService);
private readonly uploadService = inject(UploadService);
private readonly sitesService = inject(SitesService);
private readonly contentNodeSelectorPanelService = inject(ContentNodeSelectorPanelService);
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
DEFAULT_PAGINATION: Pagination = new Pagination({ DEFAULT_PAGINATION: Pagination = new Pagination({
maxItems: 25, maxItems: 25,
@@ -304,16 +312,6 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(
private customResourcesService: CustomResourcesService,
private queryBuilderService: SearchQueryBuilderService,
private userPreferencesService: UserPreferencesService,
private nodesApiService: NodesApiService,
private uploadService: UploadService,
private sitesService: SitesService,
private contentNodeSelectorPanelService: ContentNodeSelectorPanelService
) {}
set chosenNode(value: Node[]) { set chosenNode(value: Node[]) {
this._chosenNode = value; this._chosenNode = value;
this.select.next(value); this.select.next(value);
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, DestroyRef, inject, Inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { EmptyListComponent, IconModule, NotificationService, ToolbarComponent, ToolbarTitleComponent, TranslationService } from '@alfresco/adf-core'; import { EmptyListComponent, IconModule, NotificationService, ToolbarComponent, ToolbarTitleComponent, TranslationService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
@@ -62,6 +62,14 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ContentNodeSelectorComponent implements OnInit { export class ContentNodeSelectorComponent implements OnInit {
private readonly translation = inject(TranslationService);
private readonly contentService = inject(ContentService);
private readonly notificationService = inject(NotificationService);
private readonly uploadService = inject(UploadService);
private readonly dialog = inject<MatDialogRef<ContentNodeSelectorComponent>>(MatDialogRef);
private readonly overlayContainer = inject(OverlayContainer);
data = inject<ContentNodeSelectorComponentData>(MAT_DIALOG_DATA);
title: string; title: string;
action: NodeAction; action: NodeAction;
buttonActionName: string; buttonActionName: string;
@@ -78,15 +86,9 @@ export class ContentNodeSelectorComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor( constructor() {
private translation: TranslationService, const data = this.data;
private contentService: ContentService,
private notificationService: NotificationService,
private uploadService: UploadService,
private dialog: MatDialogRef<ContentNodeSelectorComponent>,
private overlayContainer: OverlayContainer,
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData
) {
this.action = data.actionName ?? NodeAction.CHOOSE; this.action = data.actionName ?? NodeAction.CHOOSE;
this.buttonActionName = `NODE_SELECTOR.${this.action}`; this.buttonActionName = `NODE_SELECTOR.${this.action}`;
this.title = data.title; this.title = data.title;
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation, inject } from '@angular/core';
import { InfiniteSelectScrollDirective, AuthenticationService } from '@alfresco/adf-core'; import { InfiniteSelectScrollDirective, AuthenticationService } from '@alfresco/adf-core';
import { SitePaging, SiteEntry, Site } from '@alfresco/js-api'; import { SitePaging, SiteEntry, Site } from '@alfresco/js-api';
import { MatSelectChange, MatSelectModule } from '@angular/material/select'; import { MatSelectChange, MatSelectModule } from '@angular/material/select';
@@ -43,6 +43,11 @@ export type Relations = (typeof Relations)[keyof typeof Relations];
host: { class: 'adf-sites-dropdown' } host: { class: 'adf-sites-dropdown' }
}) })
export class DropdownSitesComponent implements OnInit { export class DropdownSitesComponent implements OnInit {
private readonly authService = inject(AuthenticationService);
private readonly sitesService = inject(SitesService);
private readonly liveAnnouncer = inject(LiveAnnouncer);
private readonly translateService = inject(TranslateService);
/** Hide the "My Files" option. */ /** Hide the "My Files" option. */
@Input() @Input()
hideMyFiles: boolean = false; hideMyFiles: boolean = false;
@@ -95,13 +100,6 @@ export class DropdownSitesComponent implements OnInit {
return this.loading; return this.loading;
} }
constructor(
private authService: AuthenticationService,
private sitesService: SitesService,
private liveAnnouncer: LiveAnnouncer,
private translateService: TranslateService
) {}
ngOnInit() { ngOnInit() {
if (!this.siteList) { if (!this.siteList) {
this.loadSiteList(); this.loadSiteList();
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewChild, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatSlideToggleChange, MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatSlideToggleChange, MatSlideToggleModule } from '@angular/material/slide-toggle';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@@ -59,7 +59,14 @@ interface SharedDialogFormProps {
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ShareDialogComponent implements OnInit { export class ShareDialogComponent implements OnInit {
private minDateValidator = (control: FormControl<Date>): any => private readonly sharedLinksApiService = inject(SharedLinksApiService);
private readonly dialogRef = inject<MatDialogRef<ShareDialogComponent>>(MatDialogRef);
private readonly dialog = inject(MatDialog);
private readonly contentService = inject(ContentService);
private readonly renditionService = inject(RenditionService);
data = inject<ContentNodeShareSettings>(MAT_DIALOG_DATA);
private readonly minDateValidator = (control: FormControl<Date>): any =>
isBefore(endOfDay(new Date(control.value)), this.minDate) ? { invalidDate: true } : null; isBefore(endOfDay(new Date(control.value)), this.minDate) ? { invalidDate: true } : null;
minDate = add(new Date(), { days: 1 }); minDate = add(new Date(), { days: 1 });
@@ -77,14 +84,6 @@ export class ShareDialogComponent implements OnInit {
@ViewChild('slideToggleExpirationDate', { static: true }) @ViewChild('slideToggleExpirationDate', { static: true })
slideToggleExpirationDate; slideToggleExpirationDate;
constructor(
private sharedLinksApiService: SharedLinksApiService,
private dialogRef: MatDialogRef<ShareDialogComponent>,
private dialog: MatDialog,
private contentService: ContentService,
private renditionService: RenditionService,
@Inject(MAT_DIALOG_DATA) public data: ContentNodeShareSettings
) {}
ngOnInit() { ngOnInit() {
if (this.data.node?.entry) { if (this.data.node?.entry) {
@@ -29,6 +29,10 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
exportAs: 'adfShare' exportAs: 'adfShare'
}) })
export class NodeSharedDirective implements OnChanges { export class NodeSharedDirective implements OnChanges {
private readonly dialog = inject(MatDialog);
private readonly zone = inject(NgZone);
private readonly alfrescoApiService = inject(AlfrescoApiService);
isFile: boolean = false; isFile: boolean = false;
isShared: boolean = false; isShared: boolean = false;
@@ -48,8 +52,6 @@ export class NodeSharedDirective implements OnChanges {
} }
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(private dialog: MatDialog, private zone: NgZone, private alfrescoApiService: AlfrescoApiService) {}
shareNode(nodeEntry: NodeEntry) { shareNode(nodeEntry: NodeEntry) {
if (nodeEntry?.entry?.isFile) { if (nodeEntry?.entry?.isFile) {
// shared and favorite // shared and favorite
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { NodePaging, SharedLinkBodyCreate, SharedLinkEntry, SharedlinksApi } from '@alfresco/js-api'; import { NodePaging, SharedLinkBodyCreate, SharedLinkEntry, SharedlinksApi } from '@alfresco/js-api';
import { Observable, from, of, Subject } from 'rxjs'; import { Observable, from, of, Subject } from 'rxjs';
import { UserPreferencesService } from '@alfresco/adf-core'; import { UserPreferencesService } from '@alfresco/adf-core';
@@ -26,6 +26,9 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
providedIn: 'root' providedIn: 'root'
}) })
export class SharedLinksApiService { export class SharedLinksApiService {
private readonly apiService = inject(AlfrescoApiService);
private readonly preferences = inject(UserPreferencesService);
error = new Subject<{ statusCode: number; message: string }>(); error = new Subject<{ statusCode: number; message: string }>();
private _sharedLinksApi: SharedlinksApi; private _sharedLinksApi: SharedlinksApi;
@@ -34,8 +37,6 @@ export class SharedLinksApiService {
return this._sharedLinksApi; return this._sharedLinksApi;
} }
constructor(private apiService: AlfrescoApiService, private preferences: UserPreferencesService) {}
/** /**
* Gets shared links available to the current user. * Gets shared links available to the current user.
* *
@@ -16,7 +16,7 @@
*/ */
import { TypeEntry } from '@alfresco/js-api'; import { TypeEntry } from '@alfresco/js-api';
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { ContentTypeDialogComponentData } from './content-type-metadata.interface'; import { ContentTypeDialogComponentData } from './content-type-metadata.interface';
import { ContentTypeService } from './content-type.service'; import { ContentTypeService } from './content-type.service';
@@ -34,6 +34,10 @@ import { MatButtonModule } from '@angular/material/button';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ContentTypeDialogComponent implements OnInit { export class ContentTypeDialogComponent implements OnInit {
private readonly dialog = inject<MatDialogRef<ContentTypeDialogComponent>>(MatDialogRef);
data = inject<ContentTypeDialogComponentData>(MAT_DIALOG_DATA);
private readonly contentTypeService = inject(ContentTypeService);
title: string; title: string;
description: string; description: string;
nodeType: string; nodeType: string;
@@ -44,11 +48,9 @@ export class ContentTypeDialogComponent implements OnInit {
propertyColumns: string[] = ['name', 'title', 'dataType']; propertyColumns: string[] = ['name', 'title', 'dataType'];
constructor( constructor() {
private dialog: MatDialogRef<ContentTypeDialogComponent>, const data = this.data;
@Inject(MAT_DIALOG_DATA) public data: ContentTypeDialogComponentData,
private contentTypeService: ContentTypeService
) {
this.title = data.title; this.title = data.title;
this.description = data.description; this.description = data.description;
this.confirmMessage = data.confirmMessage; this.confirmMessage = data.confirmMessage;
@@ -16,7 +16,7 @@
*/ */
import { TypeEntry, TypePaging, TypesApi } from '@alfresco/js-api'; import { TypeEntry, TypePaging, TypesApi } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
@@ -25,14 +25,14 @@ import { map } from 'rxjs/operators';
providedIn: 'root' providedIn: 'root'
}) })
export class ContentTypeService { export class ContentTypeService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _typesApi: TypesApi; private _typesApi: TypesApi;
get typesApi(): TypesApi { get typesApi(): TypesApi {
this._typesApi = this._typesApi ?? new TypesApi(this.alfrescoApiService.getInstance()); this._typesApi = this._typesApi ?? new TypesApi(this.alfrescoApiService.getInstance());
return this._typesApi; return this._typesApi;
} }
constructor(private alfrescoApiService: AlfrescoApiService) {}
getContentTypeByPrefix(prefixedType: string): Observable<TypeEntry> { getContentTypeByPrefix(prefixedType: string): Observable<TypeEntry> {
return from(this.typesApi.getType(prefixedType)); return from(this.typesApi.getType(prefixedType));
} }
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { Category } from '@alfresco/js-api'; import { Category } from '@alfresco/js-api';
@@ -37,15 +37,13 @@ export interface CategorySelectorDialogOptions {
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class CategorySelectorDialogComponent implements OnInit { export class CategorySelectorDialogComponent implements OnInit {
private readonly dialog = inject<MatDialogRef<CategorySelectorDialogComponent, boolean>>(MatDialogRef);
private readonly options = inject<CategorySelectorDialogOptions>(MAT_DIALOG_DATA);
categories: Category[] = []; categories: Category[] = [];
categoriesManagementMode = CategoriesManagementMode.ASSIGN; categoriesManagementMode = CategoriesManagementMode.ASSIGN;
multiSelect = true; multiSelect = true;
constructor(
private dialog: MatDialogRef<CategorySelectorDialogComponent, boolean>,
@Inject(MAT_DIALOG_DATA) private options: CategorySelectorDialogOptions
) {}
ngOnInit() { ngOnInit() {
this.multiSelect = this.options.multiSelect ?? true; this.multiSelect = this.options.multiSelect ?? true;
} }
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
import { NodesApiService } from '../../common/services/nodes-api.service'; import { NodesApiService } from '../../common/services/nodes-api.service';
import { DownloadZipService } from './services/download-zip.service'; import { DownloadZipService } from './services/download-zip.service';
@@ -35,20 +35,17 @@ import { MatButtonModule } from '@angular/material/button';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class DownloadZipDialogComponent implements OnInit { export class DownloadZipDialogComponent implements OnInit {
private readonly dialogRef = inject<MatDialogRef<DownloadZipDialogComponent>>(MatDialogRef);
data = inject(MAT_DIALOG_DATA);
private readonly downloadZipService = inject(DownloadZipService);
private readonly nodeService = inject(NodesApiService);
private readonly contentService = inject(ContentService);
// flag for async threads // flag for async threads
cancelled = false; cancelled = false;
downloadId: string; downloadId: string;
percentageDone = 0; percentageDone = 0;
constructor(
private dialogRef: MatDialogRef<DownloadZipDialogComponent>,
@Inject(MAT_DIALOG_DATA)
public data: any,
private downloadZipService: DownloadZipService,
private nodeService: NodesApiService,
private contentService: ContentService
) {}
ngOnInit() { ngOnInit() {
if (this.data?.nodeIds?.length > 0) { if (this.data?.nodeIds?.length > 0) {
if (!this.cancelled) { if (!this.cancelled) {
@@ -16,7 +16,7 @@
*/ */
import { DownloadEntry, DownloadBodyCreate, DownloadsApi } from '@alfresco/js-api'; import { DownloadEntry, DownloadBodyCreate, DownloadsApi } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Observable, from } from 'rxjs'; import { Observable, from } from 'rxjs';
import { AlfrescoApiService } from '../../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../../services/alfresco-api.service';
@@ -24,14 +24,14 @@ import { AlfrescoApiService } from '../../../services/alfresco-api.service';
providedIn: 'root' providedIn: 'root'
}) })
export class DownloadZipService { export class DownloadZipService {
private readonly apiService = inject(AlfrescoApiService);
private _downloadsApi: DownloadsApi; private _downloadsApi: DownloadsApi;
get downloadsApi(): DownloadsApi { get downloadsApi(): DownloadsApi {
this._downloadsApi = this._downloadsApi ?? new DownloadsApi(this.apiService.getInstance()); this._downloadsApi = this._downloadsApi ?? new DownloadsApi(this.apiService.getInstance());
return this._downloadsApi; return this._downloadsApi;
} }
constructor(private apiService: AlfrescoApiService) {}
/** /**
* Creates a new download. * Creates a new download.
* *
@@ -16,7 +16,7 @@
*/ */
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Component, DestroyRef, EventEmitter, inject, Inject, OnInit, Optional, Output, ViewEncapsulation } from '@angular/core'; import { Component, DestroyRef, EventEmitter, inject, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
@@ -49,6 +49,12 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
host: { class: 'adf-folder-dialog' } host: { class: 'adf-folder-dialog' }
}) })
export class FolderDialogComponent implements OnInit { export class FolderDialogComponent implements OnInit {
private readonly formBuilder = inject(UntypedFormBuilder);
private readonly dialog = inject<MatDialogRef<FolderDialogComponent>>(MatDialogRef);
private readonly nodesApi = inject(NodesApiService);
private readonly translation = inject(TranslationService);
data = inject(MAT_DIALOG_DATA, { optional: true });
/** /**
* Emitted when the edit/create folder give error for example a folder with same name already exist * Emitted when the edit/create folder give error for example a folder with same name already exist
*/ */
@@ -94,17 +100,11 @@ export class FolderDialogComponent implements OnInit {
} }
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
private readonly notificationService = inject(NotificationService) private readonly notificationService = inject(NotificationService);
constructor() {
const data = this.data;
constructor(
private formBuilder: UntypedFormBuilder,
private dialog: MatDialogRef<FolderDialogComponent>,
private nodesApi: NodesApiService,
private translation: TranslationService,
@Optional()
@Inject(MAT_DIALOG_DATA)
public data: any
) {
if (data) { if (data) {
this.editTitle = data.editTitle || this.editTitle; this.editTitle = data.editTitle || this.editTitle;
this.createTitle = data.createTitle || this.createTitle; this.createTitle = data.createTitle || this.createTitle;
@@ -68,6 +68,12 @@ interface VisibilityOption {
host: { class: 'adf-library-dialog' } host: { class: 'adf-library-dialog' }
}) })
export class LibraryDialogComponent implements OnInit { export class LibraryDialogComponent implements OnInit {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly sitesService = inject(SitesService);
private readonly formBuilder = inject(UntypedFormBuilder);
private readonly dialog = inject<MatDialogRef<LibraryDialogComponent>>(MatDialogRef);
private readonly notificationService = inject(NotificationService);
/** Emitted when an error occurs. */ /** Emitted when an error occurs. */
@Output() @Output()
error = new EventEmitter<any>(); error = new EventEmitter<any>();
@@ -103,14 +109,6 @@ export class LibraryDialogComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(
private alfrescoApiService: AlfrescoApiService,
private sitesService: SitesService,
private formBuilder: UntypedFormBuilder,
private dialog: MatDialogRef<LibraryDialogComponent>,
private notificationService: NotificationService
) {}
ngOnInit() { ngOnInit() {
const validators = { const validators = {
id: [Validators.required, Validators.maxLength(72), this.forbidSpecialCharacters], id: [Validators.required, Validators.maxLength(72), this.forbidSpecialCharacters],
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, OnInit, Optional, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { differenceInSeconds } from 'date-fns'; import { differenceInSeconds } from 'date-fns';
@@ -46,6 +46,11 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class NodeLockDialogComponent implements OnInit { export class NodeLockDialogComponent implements OnInit {
private readonly formBuilder = inject(UntypedFormBuilder);
dialog = inject<MatDialogRef<NodeLockDialogComponent>>(MatDialogRef);
private readonly alfrescoApi = inject(AlfrescoApiService);
data = inject(MAT_DIALOG_DATA, { optional: true });
form: UntypedFormGroup; form: UntypedFormGroup;
node: Node = null; node: Node = null;
nodeName: string; nodeName: string;
@@ -56,15 +61,6 @@ export class NodeLockDialogComponent implements OnInit {
return this._nodesApi; return this._nodesApi;
} }
constructor(
private formBuilder: UntypedFormBuilder,
public dialog: MatDialogRef<NodeLockDialogComponent>,
private alfrescoApi: AlfrescoApiService,
@Optional()
@Inject(MAT_DIALOG_DATA)
public data: any
) {}
ngOnInit() { ngOnInit() {
const { node } = this.data; const { node } = this.data;
this.nodeName = node.name; this.nodeName = node.name;
@@ -15,14 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { AfterContentInit, Directive, ElementRef } from '@angular/core'; import { AfterContentInit, Directive, ElementRef, inject } from '@angular/core';
@Directive({ @Directive({
standalone: true, standalone: true,
selector: '[adf-auto-focus]' selector: '[adf-auto-focus]'
}) })
export class AutoFocusDirective implements AfterContentInit { export class AutoFocusDirective implements AfterContentInit {
public constructor(private el: ElementRef) {} private readonly el = inject(ElementRef);
public ngAfterContentInit() { public ngAfterContentInit() {
setTimeout(() => { setTimeout(() => {
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Directive, HostListener, Input, OnChanges, Output, EventEmitter, SimpleChanges } from '@angular/core'; import { Directive, HostListener, Input, OnChanges, Output, EventEmitter, SimpleChanges, inject } from '@angular/core';
import { FavoriteBodyCreate, FavoritesApi } from '@alfresco/js-api'; import { FavoriteBodyCreate, FavoritesApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
import { LibraryEntity } from '../interfaces/library-entity.interface'; import { LibraryEntity } from '../interfaces/library-entity.interface';
@@ -27,6 +27,9 @@ import { NotificationService } from '@alfresco/adf-core';
exportAs: 'favoriteLibrary' exportAs: 'favoriteLibrary'
}) })
export class LibraryFavoriteDirective implements OnChanges { export class LibraryFavoriteDirective implements OnChanges {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly notificationService = inject(NotificationService);
@Input('adf-favorite-library') @Input('adf-favorite-library')
library: LibraryEntity = null; library: LibraryEntity = null;
@@ -59,8 +62,6 @@ export class LibraryFavoriteDirective implements OnChanges {
} }
} }
constructor(private readonly alfrescoApiService: AlfrescoApiService, private readonly notificationService: NotificationService) {}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (!changes.library.currentValue) { if (!changes.library.currentValue) {
this.targetLibrary = null; this.targetLibrary = null;
@@ -18,28 +18,39 @@
import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { LibraryMembershipDirective } from './library-membership.directive'; import { LibraryMembershipDirective } from './library-membership.directive';
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { of, throwError, Subject } from 'rxjs'; import { of, throwError } from 'rxjs';
import { SitesService } from '../common/services/sites.service'; import { SitesService } from '../common/services/sites.service';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock'; import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
import { VersionCompatibilityService } from '../version-compatibility/version-compatibility.service';
describe('LibraryMembershipDirective', () => { describe('LibraryMembershipDirective', () => {
let alfrescoApiService: AlfrescoApiService;
let directive: LibraryMembershipDirective; let directive: LibraryMembershipDirective;
let sitesService: SitesService; let sitesService: SitesService;
let versionCompatibilityService: jasmine.SpyObj<VersionCompatibilityService>;
let addMembershipSpy: jasmine.Spy; let addMembershipSpy: jasmine.Spy;
let getMembershipSpy: jasmine.Spy; let getMembershipSpy: jasmine.Spy;
let deleteMembershipSpy: jasmine.Spy; let deleteMembershipSpy: jasmine.Spy;
let mockSupportedVersion = false; let mockSupportedVersion = false;
let testSiteEntry: any; let testSiteEntry: Partial<{ id: string; guid: string; title: string; visibility: string }>;
let requestedMembershipResponse: any; let requestedMembershipResponse: Partial<{ id: string; createdAt: string; site: typeof testSiteEntry }>;
beforeEach(() => { beforeEach(() => {
versionCompatibilityService = jasmine.createSpyObj('VersionCompatibilityService', ['isVersionSupported']);
versionCompatibilityService.isVersionSupported.and.callFake(() => mockSupportedVersion);
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule], providers: [
providers: [SitesService, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] LibraryMembershipDirective,
SitesService,
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
{ provide: VersionCompatibilityService, useValue: versionCompatibilityService },
provideHttpClient(),
provideHttpClientTesting()
]
}); });
testSiteEntry = { testSiteEntry = {
@@ -55,18 +66,14 @@ describe('LibraryMembershipDirective', () => {
site: testSiteEntry site: testSiteEntry
}; };
alfrescoApiService = TestBed.inject(AlfrescoApiService);
sitesService = TestBed.inject(SitesService); sitesService = TestBed.inject(SitesService);
directive = new LibraryMembershipDirective(alfrescoApiService, sitesService, { directive = TestBed.inject(LibraryMembershipDirective);
ecmProductInfo$: new Subject(),
isVersionSupported: () => mockSupportedVersion
} as any);
}); });
describe('markMembershipRequest', () => { describe('markMembershipRequest', () => {
beforeEach(() => { beforeEach(() => {
getMembershipSpy = spyOn(directive.sitesApi, 'getSiteMembershipRequestForPerson').and.returnValue( getMembershipSpy = spyOn(directive.sitesApi, 'getSiteMembershipRequestForPerson').and.returnValue(
Promise.resolve({ entry: requestedMembershipResponse }) Promise.resolve({ entry: requestedMembershipResponse } as never)
); );
}); });
@@ -109,10 +116,10 @@ describe('LibraryMembershipDirective', () => {
beforeEach(() => { beforeEach(() => {
mockSupportedVersion = false; mockSupportedVersion = false;
getMembershipSpy = spyOn(directive.sitesApi, 'getSiteMembershipRequestForPerson').and.returnValue( getMembershipSpy = spyOn(directive.sitesApi, 'getSiteMembershipRequestForPerson').and.returnValue(
Promise.resolve({ entry: requestedMembershipResponse }) Promise.resolve({ entry: requestedMembershipResponse } as never)
); );
addMembershipSpy = spyOn(directive.sitesApi, 'createSiteMembershipRequestForPerson').and.returnValue( addMembershipSpy = spyOn(directive.sitesApi, 'createSiteMembershipRequestForPerson').and.returnValue(
Promise.resolve({ entry: requestedMembershipResponse }) Promise.resolve({ entry: requestedMembershipResponse } as never)
); );
deleteMembershipSpy = spyOn(directive.sitesApi, 'deleteSiteMembershipRequestForPerson').and.returnValue(Promise.resolve()); deleteMembershipSpy = spyOn(directive.sitesApi, 'deleteSiteMembershipRequestForPerson').and.returnValue(Promise.resolve());
}); });
@@ -162,7 +169,7 @@ describe('LibraryMembershipDirective', () => {
})); }));
it('should call API to add user to library if admin user', fakeAsync(() => { it('should call API to add user to library if admin user', fakeAsync(() => {
const createSiteMembershipSpy = spyOn(sitesService, 'createSiteMembership').and.returnValue(of({} as any)); const createSiteMembershipSpy = spyOn(sitesService, 'createSiteMembership').and.returnValue(of({} as never));
const selection = { entry: { id: 'no-membership-requested' } }; const selection = { entry: { id: 'no-membership-requested' } };
const selectionChange = new SimpleChange(null, selection, true); const selectionChange = new SimpleChange(null, selection, true);
directive.isAdmin = true; directive.isAdmin = true;
@@ -176,7 +183,7 @@ describe('LibraryMembershipDirective', () => {
it('should emit error when the request to join a library fails', fakeAsync(() => { it('should emit error when the request to join a library fails', fakeAsync(() => {
spyOn(directive.error, 'emit'); spyOn(directive.error, 'emit');
addMembershipSpy.and.returnValue(throwError('err')); addMembershipSpy.and.returnValue(throwError(() => 'err'));
const selection = { entry: { id: 'no-membership-requested' } }; const selection = { entry: { id: 'no-membership-requested' } };
const change = new SimpleChange(null, selection, true); const change = new SimpleChange(null, selection, true);
@@ -206,7 +213,7 @@ describe('LibraryMembershipDirective', () => {
]; ];
testData.forEach((data) => { testData.forEach((data) => {
addMembershipSpy.and.returnValue(throwError({ message: data.fixture })); addMembershipSpy.and.returnValue(throwError(() => ({ message: data.fixture })));
emitErrorSpy.calls.reset(); emitErrorSpy.calls.reset();
directive.toggleMembershipRequest(); directive.toggleMembershipRequest();
tick(); tick();
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges, inject } from '@angular/core';
import { SiteEntry, SiteMembershipRequestBodyCreate, SiteMembershipRequestEntry, SitesApi } from '@alfresco/js-api'; import { SiteEntry, SiteMembershipRequestBodyCreate, SiteMembershipRequestEntry, SitesApi } from '@alfresco/js-api';
import { BehaviorSubject, from, Observable } from 'rxjs'; import { BehaviorSubject, from, Observable } from 'rxjs';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
@@ -30,6 +30,10 @@ import { SitesService } from '../common/services/sites.service';
exportAs: 'libraryMembership' exportAs: 'libraryMembership'
}) })
export class LibraryMembershipDirective implements OnChanges { export class LibraryMembershipDirective implements OnChanges {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly sitesService = inject(SitesService);
private readonly versionCompatibilityService = inject(VersionCompatibilityService);
targetSite: any = null; targetSite: any = null;
isJoinRequested: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); isJoinRequested: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
@@ -60,12 +64,6 @@ export class LibraryMembershipDirective implements OnChanges {
this.toggleMembershipRequest(); this.toggleMembershipRequest();
} }
constructor(
private alfrescoApiService: AlfrescoApiService,
private sitesService: SitesService,
private versionCompatibilityService: VersionCompatibilityService
) {}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (!changes.selection.currentValue?.entry) { if (!changes.selection.currentValue?.entry) {
this.targetSite = null; this.targetSite = null;
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Directive, Input, Component, OnInit, OnChanges, ViewContainerRef } from '@angular/core'; import { Directive, Input, Component, OnInit, OnChanges, ViewContainerRef, inject } from '@angular/core';
import { TranslatePipe } from '@ngx-translate/core'; import { TranslatePipe } from '@ngx-translate/core';
@Directive({ @Directive({
@@ -23,14 +23,14 @@ import { TranslatePipe } from '@ngx-translate/core';
selector: '[adf-node-counter]' selector: '[adf-node-counter]'
}) })
export class NodeCounterDirective implements OnInit, OnChanges { export class NodeCounterDirective implements OnInit, OnChanges {
private readonly viewContainerRef = inject(ViewContainerRef);
/** Number to display in the counter badge */ /** Number to display in the counter badge */
@Input('adf-node-counter') @Input('adf-node-counter')
counter: number; counter: number;
componentRef: NodeCounterComponent; componentRef: NodeCounterComponent;
constructor(private viewContainerRef: ViewContainerRef) {}
ngOnInit() { ngOnInit() {
this.componentRef = this.viewContainerRef.createComponent(NodeCounterComponent).instance; this.componentRef = this.viewContainerRef.createComponent(NodeCounterComponent).instance;
this.componentRef.counter = this.counter; this.componentRef.counter = this.counter;
@@ -47,7 +47,7 @@ export class NodeCounterDirective implements OnInit, OnChanges {
standalone: true, standalone: true,
imports: [TranslatePipe], imports: [TranslatePipe],
selector: 'adf-node-counter', selector: 'adf-node-counter',
template: ` <div>{{ 'NODE_COUNTER.SELECTED_COUNT' | translate : { count: counter } }}</div> ` template: ` <div>{{ 'NODE_COUNTER.SELECTED_COUNT' | translate: { count: counter } }}</div> `
}) })
export class NodeCounterComponent { export class NodeCounterComponent {
counter: number; counter: number;
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/no-input-rename */ /* eslint-disable @angular-eslint/no-input-rename */
import { Directive, ElementRef, EventEmitter, HostListener, Input, OnChanges, Output } from '@angular/core'; import { Directive, ElementRef, EventEmitter, HostListener, Input, OnChanges, Output, inject } from '@angular/core';
import { NodeEntry, Node, DeletedNodeEntry, DeletedNode, TrashcanApi, NodesApi } from '@alfresco/js-api'; import { NodeEntry, Node, DeletedNodeEntry, DeletedNode, TrashcanApi, NodesApi } from '@alfresco/js-api';
import { Observable, forkJoin, from, of } from 'rxjs'; import { Observable, forkJoin, from, of } from 'rxjs';
import { TranslationService } from '@alfresco/adf-core'; import { TranslationService } from '@alfresco/adf-core';
@@ -51,6 +51,10 @@ interface ProcessStatus {
selector: '[adf-delete]' selector: '[adf-delete]'
}) })
export class NodeDeleteDirective implements OnChanges { export class NodeDeleteDirective implements OnChanges {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly translation = inject(TranslationService);
private readonly elementRef = inject(ElementRef);
/** Array of nodes to delete. */ /** Array of nodes to delete. */
@Input('adf-delete') @Input('adf-delete')
selection: NodeEntry[] | DeletedNodeEntry[]; selection: NodeEntry[] | DeletedNodeEntry[];
@@ -80,8 +84,6 @@ export class NodeDeleteDirective implements OnChanges {
this.process(this.selection); this.process(this.selection);
} }
constructor(private alfrescoApiService: AlfrescoApiService, private translation: TranslationService, private elementRef: ElementRef) {}
ngOnChanges() { ngOnChanges() {
if (!this.selection || (this.selection && this.selection.length === 0)) { if (!this.selection || (this.selection && this.selection.length === 0)) {
this.setDisableAttribute(true); this.setDisableAttribute(true);
@@ -20,7 +20,8 @@ import { By } from '@angular/platform-browser';
import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { Component, DebugElement, ViewChild } from '@angular/core'; import { Component, DebugElement, ViewChild } from '@angular/core';
import { NodeDownloadDirective } from './node-download.directive'; import { NodeDownloadDirective } from './node-download.directive';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { ContentApi } from '@alfresco/js-api'; import { ContentApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock'; import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
@@ -56,8 +57,8 @@ describe('NodeDownloadDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule, MatDialogModule, TestComponent], imports: [MatDialogModule, TestComponent],
providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }] providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, provideHttpClient(), provideHttpClientTesting()]
}); });
fixture = TestBed.createComponent(TestComponent); fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Directive, Input, HostListener } from '@angular/core'; import { Directive, Input, HostListener, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { DownloadService } from '@alfresco/adf-core'; import { DownloadService } from '@alfresco/adf-core';
import { DownloadZipDialogComponent } from '../dialogs/download-zip/download-zip.dialog'; import { DownloadZipDialogComponent } from '../dialogs/download-zip/download-zip.dialog';
@@ -31,6 +31,10 @@ import { AlfrescoApiService } from '../services/alfresco-api.service';
selector: '[adfNodeDownload]' selector: '[adfNodeDownload]'
}) })
export class NodeDownloadDirective { export class NodeDownloadDirective {
private readonly apiService = inject(AlfrescoApiService);
private readonly downloadService = inject(DownloadService);
private readonly dialog = inject(MatDialog);
private _contentApi: ContentApi; private _contentApi: ContentApi;
get contentApi(): ContentApi { get contentApi(): ContentApi {
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance()); this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
@@ -50,8 +54,6 @@ export class NodeDownloadDirective {
this.downloadNodes(this.nodes); this.downloadNodes(this.nodes);
} }
constructor(private apiService: AlfrescoApiService, private downloadService: DownloadService, private dialog: MatDialog) {}
/** /**
* Downloads multiple selected nodes. * Downloads multiple selected nodes.
* Packs result into a .ZIP archive if there is more than one node selected. * Packs result into a .ZIP archive if there is more than one node selected.
@@ -19,22 +19,19 @@ import { SimpleChange } from '@angular/core';
import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { NodeFavoriteDirective } from './node-favorite.directive'; import { NodeFavoriteDirective } from './node-favorite.directive';
import { AppConfigService, AppConfigServiceMock, NotificationService } from '@alfresco/adf-core'; import { AppConfigService, AppConfigServiceMock, NotificationService } from '@alfresco/adf-core';
import { AlfrescoApiService } from '../services';
import { provideApiTesting } from '../testing/providers'; import { provideApiTesting } from '../testing/providers';
describe('NodeFavoriteDirective', () => { describe('NodeFavoriteDirective', () => {
let directive: NodeFavoriteDirective; let directive: NodeFavoriteDirective;
let alfrescoApiService: AlfrescoApiService;
let notificationService: NotificationService; let notificationService: NotificationService;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [], imports: [],
providers: [provideApiTesting(), { provide: AppConfigService, useClass: AppConfigServiceMock }] providers: [NodeFavoriteDirective, provideApiTesting(), { provide: AppConfigService, useClass: AppConfigServiceMock }]
}); });
alfrescoApiService = TestBed.inject(AlfrescoApiService);
notificationService = TestBed.inject(NotificationService); notificationService = TestBed.inject(NotificationService);
directive = new NodeFavoriteDirective(alfrescoApiService, notificationService); directive = TestBed.inject(NodeFavoriteDirective);
}); });
describe('selection input change event', () => { describe('selection input change event', () => {
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/no-input-rename */ /* eslint-disable @angular-eslint/no-input-rename */
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges, inject } from '@angular/core';
import { FavoriteBodyCreate, NodeEntry, SharedLinkEntry, Node, SharedLink, FavoritesApi } from '@alfresco/js-api'; import { FavoriteBodyCreate, NodeEntry, SharedLinkEntry, Node, SharedLink, FavoritesApi } from '@alfresco/js-api';
import { Observable, from, forkJoin, of } from 'rxjs'; import { Observable, from, forkJoin, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators'; import { catchError, map } from 'rxjs/operators';
@@ -30,6 +30,9 @@ import { NotificationService } from '@alfresco/adf-core';
exportAs: 'adfFavorite' exportAs: 'adfFavorite'
}) })
export class NodeFavoriteDirective implements OnChanges { export class NodeFavoriteDirective implements OnChanges {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly notificationService = inject(NotificationService);
favorites: any[] = []; favorites: any[] = [];
private _favoritesApi: FavoritesApi; private _favoritesApi: FavoritesApi;
@@ -53,8 +56,6 @@ export class NodeFavoriteDirective implements OnChanges {
this.toggleFavorite(); this.toggleFavorite();
} }
constructor(private readonly alfrescoApiService: AlfrescoApiService, private readonly notificationService: NotificationService) {}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (!changes.selection.currentValue.length) { if (!changes.selection.currentValue.length) {
this.favorites = []; this.favorites = [];
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/no-input-rename */ /* eslint-disable @angular-eslint/no-input-rename */
import { Directive, ElementRef, Renderer2, HostListener, Input, AfterViewInit } from '@angular/core'; import { Directive, ElementRef, Renderer2, HostListener, Input, AfterViewInit, inject } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { ContentService } from '../common/services/content.service'; import { ContentService } from '../common/services/content.service';
import { AllowableOperationsEnum } from '../common/models/allowable-operations.enum'; import { AllowableOperationsEnum } from '../common/models/allowable-operations.enum';
@@ -28,6 +28,11 @@ import { ContentNodeDialogService } from '../content-node-selector/content-node-
selector: '[adf-node-lock]' selector: '[adf-node-lock]'
}) })
export class NodeLockDirective implements AfterViewInit { export class NodeLockDirective implements AfterViewInit {
element = inject(ElementRef);
private readonly renderer = inject(Renderer2);
private readonly contentService = inject(ContentService);
private readonly contentNodeDialogService = inject(ContentNodeDialogService);
/** Node to lock/unlock. */ /** Node to lock/unlock. */
@Input('adf-node-lock') @Input('adf-node-lock')
node: Node; node: Node;
@@ -38,13 +43,6 @@ export class NodeLockDirective implements AfterViewInit {
this.contentNodeDialogService.openLockNodeDialog(this.node); this.contentNodeDialogService.openLockNodeDialog(this.node);
} }
constructor(
public element: ElementRef,
private renderer: Renderer2,
private contentService: ContentService,
private contentNodeDialogService: ContentNodeDialogService
) {}
ngAfterViewInit() { ngAfterViewInit() {
const hasAllowableOperations = this.contentService.hasAllowableOperations(this.node, AllowableOperationsEnum.LOCK); const hasAllowableOperations = this.contentService.hasAllowableOperations(this.node, AllowableOperationsEnum.LOCK);
this.renderer.setProperty(this.element.nativeElement, 'disabled', !hasAllowableOperations); this.renderer.setProperty(this.element.nativeElement, 'disabled', !hasAllowableOperations);
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */ /* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core'; import { Directive, EventEmitter, HostListener, Input, Output, inject } from '@angular/core';
import { TrashcanApi, DeletedNodeEntry, DeletedNodesPaging } from '@alfresco/js-api'; import { TrashcanApi, DeletedNodeEntry, DeletedNodesPaging } from '@alfresco/js-api';
import { Observable, forkJoin, from, of } from 'rxjs'; import { Observable, forkJoin, from, of } from 'rxjs';
import { tap, mergeMap, map, catchError } from 'rxjs/operators'; import { tap, mergeMap, map, catchError } from 'rxjs/operators';
@@ -30,6 +30,9 @@ import { AlfrescoApiService } from '../services/alfresco-api.service';
selector: '[adf-restore]' selector: '[adf-restore]'
}) })
export class NodeRestoreDirective { export class NodeRestoreDirective {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly translation = inject(TranslationService);
private readonly restoreProcessStatus; private readonly restoreProcessStatus;
private _trashcanApi: TrashcanApi; private _trashcanApi: TrashcanApi;
@@ -51,7 +54,7 @@ export class NodeRestoreDirective {
this.recover(this.selection); this.recover(this.selection);
} }
constructor(private alfrescoApiService: AlfrescoApiService, private translation: TranslationService) { constructor() {
this.restoreProcessStatus = this.processStatus(); this.restoreProcessStatus = this.processStatus();
} }
@@ -29,11 +29,19 @@ describe('ContentColumnList', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule] imports: [NoopAuthModule]
}); });
documentList = TestBed.createComponent(DocumentListComponent).componentInstance as DocumentListComponent;
actionList = new ContentActionListComponent(documentList); const docListFixture = TestBed.createComponent(DocumentListComponent);
documentList = docListFixture.componentInstance;
}); });
it('should register action', () => { it('should register action', () => {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [NoopAuthModule],
providers: [{ provide: DocumentListComponent, useValue: documentList }, ContentActionListComponent]
});
actionList = TestBed.inject(ContentActionListComponent);
spyOn(documentList.actions, 'push').and.callThrough(); spyOn(documentList.actions, 'push').and.callThrough();
const action = new ContentActionModel(); const action = new ContentActionModel();
@@ -44,12 +52,24 @@ describe('ContentColumnList', () => {
}); });
it('should require document list instance to register action', () => { it('should require document list instance to register action', () => {
actionList = new ContentActionListComponent(null); TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [NoopAuthModule],
providers: [{ provide: DocumentListComponent, useValue: null }, ContentActionListComponent]
});
actionList = TestBed.inject(ContentActionListComponent);
const action = new ContentActionModel(); const action = new ContentActionModel();
expect(actionList.registerAction(action)).toBeFalsy(); expect(actionList.registerAction(action)).toBeFalsy();
}); });
it('should require action instance to register', () => { it('should require action instance to register', () => {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [NoopAuthModule],
providers: [{ provide: DocumentListComponent, useValue: documentList }, ContentActionListComponent]
});
actionList = TestBed.inject(ContentActionListComponent);
spyOn(documentList.actions, 'push').and.callThrough(); spyOn(documentList.actions, 'push').and.callThrough();
const result = actionList.registerAction(null); const result = actionList.registerAction(null);
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
import { Component } from '@angular/core'; import { Component, inject } from '@angular/core';
import { ContentActionModel } from './../../models/content-action.model'; import { ContentActionModel } from './../../models/content-action.model';
import { DocumentListComponent } from './../document-list.component'; import { DocumentListComponent } from './../document-list.component';
@@ -26,7 +26,7 @@ import { DocumentListComponent } from './../document-list.component';
template: '' template: ''
}) })
export class ContentActionListComponent { export class ContentActionListComponent {
constructor(private documentList: DocumentListComponent) {} private readonly documentList = inject(DocumentListComponent);
/** /**
* Registers action handler within the parent document list component. * Registers action handler within the parent document list component.
@@ -21,46 +21,55 @@ import { FileNode } from '../../../mock';
import { ContentActionModel } from './../../models/content-action.model'; import { ContentActionModel } from './../../models/content-action.model';
import { DocumentActionsService } from './../../services/document-actions.service'; import { DocumentActionsService } from './../../services/document-actions.service';
import { FolderActionsService } from './../../services/folder-actions.service'; import { FolderActionsService } from './../../services/folder-actions.service';
import { NodeActionsService } from './../../services/node-actions.service';
import { DocumentListComponent } from './../document-list.component'; import { DocumentListComponent } from './../document-list.component';
import { ContentActionListComponent } from './content-action-list.component'; import { ContentActionListComponent } from './content-action-list.component';
import { ContentActionComponent } from './content-action.component'; import { ContentActionComponent } from './content-action.component';
import { ContentService } from '../../../common/services/content.service';
import { NoopAuthModule } from '@alfresco/adf-core'; import { NoopAuthModule } from '@alfresco/adf-core';
describe('ContentAction', () => { describe('ContentAction', () => {
let documentList: DocumentListComponent; let documentList: DocumentListComponent;
let actionList: ContentActionListComponent; let actionList: ContentActionListComponent;
let documentActions: DocumentActionsService; let documentActionsService: DocumentActionsService;
let folderActions: FolderActionsService; let folderActionsService: FolderActionsService;
let contentService: ContentService;
let nodeActionsService: NodeActionsService;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule] imports: [NoopAuthModule]
}); });
contentService = TestBed.inject(ContentService);
nodeActionsService = new NodeActionsService(null, null, null);
documentActions = new DocumentActionsService(nodeActionsService, null, null, null);
folderActions = new FolderActionsService(nodeActionsService, null, contentService, null);
documentList = TestBed.createComponent(DocumentListComponent).componentInstance as DocumentListComponent; const docListFixture = TestBed.createComponent(DocumentListComponent);
actionList = new ContentActionListComponent(documentList); documentList = docListFixture.componentInstance;
TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [NoopAuthModule],
providers: [
{ provide: DocumentListComponent, useValue: documentList },
ContentActionListComponent,
DocumentActionsService,
FolderActionsService
]
});
actionList = TestBed.inject(ContentActionListComponent);
documentActionsService = TestBed.inject(DocumentActionsService);
folderActionsService = TestBed.inject(FolderActionsService);
});
afterEach(() => {
documentList.actions = [];
}); });
it('should register within parent actions list', () => { it('should register within parent actions list', () => {
spyOn(actionList, 'registerAction').and.stub(); spyOn(actionList, 'registerAction').and.stub();
const action = new ContentActionComponent(actionList, null, null); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
action.ngOnInit(); action.ngOnInit();
expect(actionList.registerAction).toHaveBeenCalled(); expect(actionList.registerAction).toHaveBeenCalled();
}); });
it('should setup and register model', () => { it('should setup and register model', () => {
const action = new ContentActionComponent(actionList, null, null); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
action.target = 'document'; action.target = 'document';
action.title = '<title>'; action.title = '<title>';
action.icon = '<icon>'; action.icon = '<icon>';
@@ -77,7 +86,7 @@ describe('ContentAction', () => {
}); });
it('should update visibility binding', () => { it('should update visibility binding', () => {
const action = new ContentActionComponent(actionList, null, null); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
action.target = 'document'; action.target = 'document';
action.title = '<title>'; action.title = '<title>';
action.icon = '<icon>'; action.icon = '<icon>';
@@ -96,14 +105,15 @@ describe('ContentAction', () => {
it('should get action handler from document actions service', () => { it('should get action handler from document actions service', () => {
const handler = () => {}; const handler = () => {};
spyOn(documentActions, 'getHandler').and.returnValue(handler); spyOn(documentActionsService, 'getHandler').and.returnValue(handler);
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const action = new ContentActionComponent(actionList, documentActions, null);
action.target = 'document'; action.target = 'document';
action.handler = '<handler>'; action.handler = '<handler>';
action.ngOnInit(); action.ngOnInit();
expect(documentActions.getHandler).toHaveBeenCalledWith(action.handler); expect(documentActionsService.getHandler).toHaveBeenCalledWith(action.handler);
expect(documentList.actions.length).toBe(1); expect(documentList.actions.length).toBe(1);
const model = documentList.actions[0]; const model = documentList.actions[0];
@@ -112,14 +122,15 @@ describe('ContentAction', () => {
it('should get action handler from folder actions service', () => { it('should get action handler from folder actions service', () => {
const handler = () => {}; const handler = () => {};
spyOn(folderActions, 'getHandler').and.returnValue(handler); spyOn(folderActionsService, 'getHandler').and.returnValue(handler);
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const action = new ContentActionComponent(actionList, null, folderActions);
action.target = 'folder'; action.target = 'folder';
action.handler = '<handler>'; action.handler = '<handler>';
action.ngOnInit(); action.ngOnInit();
expect(folderActions.getHandler).toHaveBeenCalledWith(action.handler); expect(folderActionsService.getHandler).toHaveBeenCalledWith(action.handler);
expect(documentList.actions.length).toBe(1); expect(documentList.actions.length).toBe(1);
const model = documentList.actions[0]; const model = documentList.actions[0];
@@ -127,69 +138,75 @@ describe('ContentAction', () => {
}); });
it('should create document and folder action when there is no target', () => { it('should create document and folder action when there is no target', () => {
spyOn(folderActions, 'getHandler').and.stub(); spyOn(folderActionsService, 'getHandler').and.stub();
spyOn(documentActions, 'getHandler').and.stub(); spyOn(documentActionsService, 'getHandler').and.stub();
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const action = new ContentActionComponent(actionList, documentActions, folderActions);
action.handler = '<handler>'; action.handler = '<handler>';
action.ngOnInit(); action.ngOnInit();
expect(documentList.actions.length).toBe(2); expect(documentList.actions.length).toBe(2);
expect(folderActions.getHandler).toHaveBeenCalled(); expect(folderActionsService.getHandler).toHaveBeenCalled();
expect(documentActions.getHandler).toHaveBeenCalled(); expect(documentActionsService.getHandler).toHaveBeenCalled();
}); });
it('should create document action when target is document', () => { it('should create document action when target is document', () => {
spyOn(folderActions, 'getHandler').and.stub(); spyOn(folderActionsService, 'getHandler').and.stub();
spyOn(documentActions, 'getHandler').and.stub(); spyOn(documentActionsService, 'getHandler').and.stub();
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const action = new ContentActionComponent(actionList, documentActions, folderActions);
action.handler = '<handler>'; action.handler = '<handler>';
action.target = 'document'; action.target = 'document';
action.ngOnInit(); action.ngOnInit();
expect(documentList.actions.length).toBe(1); expect(documentList.actions.length).toBe(1);
expect(folderActions.getHandler).not.toHaveBeenCalled(); expect(folderActionsService.getHandler).not.toHaveBeenCalled();
expect(documentActions.getHandler).toHaveBeenCalled(); expect(documentActionsService.getHandler).toHaveBeenCalled();
}); });
it('should create folder action when target is folder', () => { it('should create folder action when target is folder', () => {
spyOn(folderActions, 'getHandler').and.stub(); spyOn(folderActionsService, 'getHandler').and.stub();
spyOn(documentActions, 'getHandler').and.stub(); spyOn(documentActionsService, 'getHandler').and.stub();
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const action = new ContentActionComponent(actionList, documentActions, folderActions);
action.handler = '<handler>'; action.handler = '<handler>';
action.target = 'folder'; action.target = 'folder';
action.ngOnInit(); action.ngOnInit();
expect(documentList.actions.length).toBe(1); expect(documentList.actions.length).toBe(1);
expect(folderActions.getHandler).toHaveBeenCalled(); expect(folderActionsService.getHandler).toHaveBeenCalled();
expect(documentActions.getHandler).not.toHaveBeenCalled(); expect(documentActionsService.getHandler).not.toHaveBeenCalled();
}); });
it('should be case insensitive for document target', () => { it('should be case insensitive for document target', () => {
spyOn(documentActions, 'getHandler').and.stub(); spyOn(documentActionsService, 'getHandler').and.stub();
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const action = new ContentActionComponent(actionList, documentActions, null);
action.target = 'DoCuMeNt'; action.target = 'DoCuMeNt';
action.handler = '<handler>'; action.handler = '<handler>';
action.ngOnInit(); action.ngOnInit();
expect(documentActions.getHandler).toHaveBeenCalledWith(action.handler); expect(documentActionsService.getHandler).toHaveBeenCalledWith(action.handler);
}); });
it('should be case insensitive for folder target', () => { it('should be case insensitive for folder target', () => {
spyOn(folderActions, 'getHandler').and.stub(); spyOn(folderActionsService, 'getHandler').and.stub();
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const action = new ContentActionComponent(actionList, null, folderActions);
action.target = 'FoLdEr'; action.target = 'FoLdEr';
action.handler = '<handler>'; action.handler = '<handler>';
action.ngOnInit(); action.ngOnInit();
expect(folderActions.getHandler).toHaveBeenCalledWith(action.handler); expect(folderActionsService.getHandler).toHaveBeenCalledWith(action.handler);
}); });
it('should use custom "execute" emitter', (done) => { it('should use custom "execute" emitter', (done) => {
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const emitter = new EventEmitter(); const emitter = new EventEmitter();
emitter.subscribe((e) => { emitter.subscribe((e) => {
@@ -197,7 +214,6 @@ describe('ContentAction', () => {
done(); done();
}); });
const action = new ContentActionComponent(actionList, null, null);
action.target = 'document'; action.target = 'document';
action.execute = emitter; action.execute = emitter;
@@ -209,42 +225,44 @@ describe('ContentAction', () => {
}); });
it('should not find document action handler with missing service', () => { it('should not find document action handler with missing service', () => {
const action = new ContentActionComponent(actionList, null, null); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
expect(action.getSystemHandler('document', 'name')).toBeNull(); expect(action.getSystemHandler('document', 'name')).toBeNull();
}); });
it('should not find folder action handler with missing service', () => { it('should not find folder action handler with missing service', () => {
const action = new ContentActionComponent(actionList, null, null); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
expect(action.getSystemHandler('folder', 'name')).toBeNull(); expect(action.getSystemHandler('folder', 'name')).toBeNull();
}); });
it('should find document action handler via service', () => { it('should find document action handler via service', () => {
const handler = () => {}; const handler = () => {};
const action = new ContentActionComponent(actionList, documentActions, null); spyOn(documentActionsService, 'getHandler').and.returnValue(handler);
spyOn(documentActions, 'getHandler').and.returnValue(handler);
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
expect(action.getSystemHandler('document', 'name')).toBe(handler); expect(action.getSystemHandler('document', 'name')).toBe(handler);
}); });
it('should find folder action handler via service', () => { it('should find folder action handler via service', () => {
const handler = () => {}; const handler = () => {};
const action = new ContentActionComponent(actionList, null, folderActions); spyOn(folderActionsService, 'getHandler').and.returnValue(handler);
spyOn(folderActions, 'getHandler').and.returnValue(handler);
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
expect(action.getSystemHandler('folder', 'name')).toBe(handler); expect(action.getSystemHandler('folder', 'name')).toBe(handler);
}); });
it('should not find actions for unknown target type', () => { it('should not find actions for unknown target type', () => {
spyOn(folderActions, 'getHandler').and.stub(); spyOn(folderActionsService, 'getHandler').and.stub();
spyOn(documentActions, 'getHandler').and.stub(); spyOn(documentActionsService, 'getHandler').and.stub();
const action = new ContentActionComponent(actionList, documentActions, folderActions); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
expect(action.getSystemHandler('unknown', 'name')).toBeNull(); expect(action.getSystemHandler('unknown', 'name')).toBeNull();
expect(folderActions.getHandler).not.toHaveBeenCalled(); expect(folderActionsService.getHandler).not.toHaveBeenCalled();
expect(documentActions.getHandler).not.toHaveBeenCalled(); expect(documentActionsService.getHandler).not.toHaveBeenCalled();
}); });
it('should wire model with custom event handler', (done) => { it('should wire model with custom event handler', (done) => {
const action = new ContentActionComponent(actionList, documentActions, folderActions); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
const file = new FileNode(); const file = new FileNode();
const handler = new EventEmitter(); const handler = new EventEmitter();
@@ -260,9 +278,10 @@ describe('ContentAction', () => {
}); });
it('should allow registering model without handler', () => { it('should allow registering model without handler', () => {
const action = new ContentActionComponent(actionList, documentActions, folderActions);
spyOn(actionList, 'registerAction').and.callThrough(); spyOn(actionList, 'registerAction').and.callThrough();
const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
action.execute = null; action.execute = null;
action.handler = null; action.handler = null;
action.target = 'document'; action.target = 'document';
@@ -272,7 +291,7 @@ describe('ContentAction', () => {
}); });
it('should register on init', () => { it('should register on init', () => {
const action = new ContentActionComponent(actionList, null, null); const action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
spyOn(action, 'register').and.callThrough(); spyOn(action, 'register').and.callThrough();
action.ngOnInit(); action.ngOnInit();
@@ -281,10 +300,15 @@ describe('ContentAction', () => {
it('should require action list to register action with', () => { it('should require action list to register action with', () => {
const fakeModel = new ContentActionModel(); const fakeModel = new ContentActionModel();
let action = new ContentActionComponent(actionList, null, null); let action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
expect(action.register(fakeModel)).toBeTruthy(); expect(action.register(fakeModel)).toBeTruthy();
action = new ContentActionComponent(null, null, null); TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [NoopAuthModule],
providers: [{ provide: ContentActionListComponent, useValue: null }]
});
action = TestBed.createComponent(ContentActionComponent).componentInstance as ContentActionComponent;
expect(action.register(fakeModel)).toBeFalsy(); expect(action.register(fakeModel)).toBeFalsy();
}); });
}); });
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
import { Component, EventEmitter, Input, OnInit, Output, OnChanges, SimpleChanges, OnDestroy } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, OnChanges, SimpleChanges, OnDestroy, inject } from '@angular/core';
import { ContentActionHandler } from '../../models/content-action.model'; import { ContentActionHandler } from '../../models/content-action.model';
import { DocumentActionsService } from '../../services/document-actions.service'; import { DocumentActionsService } from '../../services/document-actions.service';
@@ -28,10 +28,13 @@ import { Subscription } from 'rxjs';
@Component({ @Component({
selector: 'content-action', selector: 'content-action',
template: '', template: ''
providers: [DocumentActionsService, FolderActionsService]
}) })
export class ContentActionComponent implements OnInit, OnChanges, OnDestroy { export class ContentActionComponent implements OnInit, OnChanges, OnDestroy {
private readonly list = inject(ContentActionListComponent);
private readonly documentActions = inject(DocumentActionsService);
private readonly folderActions = inject(FolderActionsService);
/** The title of the action as shown in the menu. */ /** The title of the action as shown in the menu. */
@Input() @Input()
title: string = 'Action'; title: string = 'Action';
@@ -91,12 +94,6 @@ export class ContentActionComponent implements OnInit, OnChanges, OnDestroy {
private subscriptions: Subscription[] = []; private subscriptions: Subscription[] = [];
constructor(
private list: ContentActionListComponent,
private documentActions: DocumentActionsService,
private folderActions: FolderActionsService
) {}
ngOnInit() { ngOnInit() {
if (this.target === ContentActionTarget.All) { if (this.target === ContentActionTarget.All) {
this.folderActionModel = this.generateAction(ContentActionTarget.Folder); this.folderActionModel = this.generateAction(ContentActionTarget.Folder);
@@ -51,7 +51,6 @@ import {
mockNodePagingWithPreselectedNodes, mockNodePagingWithPreselectedNodes,
mockPreselectedNodes mockPreselectedNodes
} from '../../mock'; } from '../../mock';
import { domSanitizerMock } from '../../testing/dom-sanitizer-mock';
import { ImageResolver } from '../data/image-resolver.model'; import { ImageResolver } from '../data/image-resolver.model';
import { RowFilter } from '../data/row-filter.model'; import { RowFilter } from '../data/row-filter.model';
import { ShareDataRow } from '../data/share-data-row.model'; import { ShareDataRow } from '../data/share-data-row.model';
@@ -1179,7 +1178,7 @@ describe('DocumentList', () => {
it('should display [empty folder] template ', () => { it('should display [empty folder] template ', () => {
fixture.detectChanges(); fixture.detectChanges();
runInInjectionContext(injector, () => { runInInjectionContext(injector, () => {
documentList.dataTable = new DataTableComponent(null, null, matIconRegistryMock, domSanitizerMock, null); documentList.dataTable = TestBed.createComponent(DataTableComponent).componentInstance as DataTableComponent;
}); });
expect(documentList.dataTable).toBeDefined(); expect(documentList.dataTable).toBeDefined();
expect(fixture.debugElement.query(By.css('adf-empty-list'))).not.toBeNull(); expect(fixture.debugElement.query(By.css('adf-empty-list'))).not.toBeNull();
@@ -1200,7 +1199,7 @@ describe('DocumentList', () => {
it('should empty folder NOT show the pagination', () => { it('should empty folder NOT show the pagination', () => {
runInInjectionContext(injector, () => { runInInjectionContext(injector, () => {
documentList.dataTable = new DataTableComponent(null, null, matIconRegistryMock, domSanitizerMock, null); documentList.dataTable = TestBed.createComponent(DataTableComponent).componentInstance as DataTableComponent;
}); });
expect(documentList.isEmpty()).toBeTruthy(); expect(documentList.isEmpty()).toBeTruthy();
@@ -112,6 +112,18 @@ const BYTES_TO_MB_CONVERSION_VALUE = 1048576;
host: { class: 'adf-document-list' } host: { class: 'adf-document-list' }
}) })
export class DocumentListComponent extends DataTableSchema implements OnInit, OnChanges, AfterContentInit, PaginatedComponent { export class DocumentListComponent extends DataTableSchema implements OnInit, OnChanges, AfterContentInit, PaginatedComponent {
private readonly documentListService = inject(DocumentListService);
private readonly elementRef = inject(ElementRef);
private readonly appConfig: AppConfigService;
private readonly userPreferencesService = inject(UserPreferencesService);
private readonly contentService = inject(ContentService);
private readonly thumbnailService = inject(ThumbnailService);
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly nodeService = inject(NodesApiService);
private readonly dataTableService = inject(DataTableService);
private readonly lockService = inject(LockService);
private readonly dialog = inject(MatDialog);
static SINGLE_CLICK_NAVIGATION: string = 'click'; static SINGLE_CLICK_NAVIGATION: string = 'click';
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick'; static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
@@ -448,7 +460,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
// @deprecated 3.0.0 // @deprecated 3.0.0
folderNode: Node; folderNode: Node;
private _pagination: PaginationModel = this.DEFAULT_PAGINATION; private readonly _pagination: PaginationModel = this.DEFAULT_PAGINATION;
pagination: BehaviorSubject<PaginationModel> = new BehaviorSubject<PaginationModel>(this.DEFAULT_PAGINATION); pagination: BehaviorSubject<PaginationModel> = new BehaviorSubject<PaginationModel>(this.DEFAULT_PAGINATION);
sortingSubject: BehaviorSubject<DataSorting[]> = new BehaviorSubject<DataSorting[]>(this.DEFAULT_SORTING); sortingSubject: BehaviorSubject<DataSorting[]> = new BehaviorSubject<DataSorting[]>(this.DEFAULT_SORTING);
@@ -463,20 +475,12 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
return this._nodesApi; return this._nodesApi;
} }
constructor( constructor() {
private documentListService: DocumentListService, const appConfig = inject(AppConfigService);
private elementRef: ElementRef,
private appConfig: AppConfigService, super('default', presetsDefaultModel);
private userPreferencesService: UserPreferencesService, this.appConfig = appConfig;
private contentService: ContentService,
private thumbnailService: ThumbnailService,
private alfrescoApiService: AlfrescoApiService,
private nodeService: NodesApiService,
private dataTableService: DataTableService,
private lockService: LockService,
private dialog: MatDialog
) {
super(appConfig, 'default', presetsDefaultModel);
this.nodeService.nodeUpdated.pipe(takeUntilDestroyed()).subscribe((node) => { this.nodeService.nodeUpdated.pipe(takeUntilDestroyed()).subscribe((node) => {
this.dataTableService.rowUpdate.next({ id: node.id, obj: { entry: node } }); this.dataTableService.rowUpdate.next({ id: node.id, obj: { entry: node } });
}); });
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject } from '@angular/core'; import { Component, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { NodeEntry } from '@alfresco/js-api'; import { NodeEntry } from '@alfresco/js-api';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@@ -29,5 +29,5 @@ import { NodeDownloadDirective } from '../../../directives/node-download.directi
templateUrl: './file-auto-download.component.html' templateUrl: './file-auto-download.component.html'
}) })
export class FileAutoDownloadComponent { export class FileAutoDownloadComponent {
constructor(@Inject(MAT_DIALOG_DATA) public node: NodeEntry) {} node = inject<NodeEntry>(MAT_DIALOG_DATA);
} }
@@ -17,7 +17,7 @@
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataTableComponent, DataSorting, PaginationModel } from '@alfresco/adf-core'; import { DataSorting, PaginationModel } from '@alfresco/adf-core';
import { SearchService } from '../../../search/services/search.service'; import { SearchService } from '../../../search/services/search.service';
import { SimpleChange } from '@angular/core'; import { SimpleChange } from '@angular/core';
import { SearchHeaderQueryBuilderService } from './../../../search/services/search-header-query-builder.service'; import { SearchHeaderQueryBuilderService } from './../../../search/services/search-header-query-builder.service';
@@ -38,7 +38,7 @@ describe('FilterHeaderComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [FilterHeaderComponent], imports: [FilterHeaderComponent],
providers: [provideRouter([]), { provide: SearchService, useValue: searchMock }, DataTableComponent] providers: [provideRouter([]), { provide: SearchService, useValue: searchMock }]
}); });
fixture = TestBed.createComponent(FilterHeaderComponent); fixture = TestBed.createComponent(FilterHeaderComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
@@ -55,6 +55,9 @@ import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
} }
}) })
export class LibraryNameColumnComponent implements OnInit { export class LibraryNameColumnComponent implements OnInit {
private readonly element = inject(ElementRef);
private readonly nodesApiService = inject(NodesApiService);
@Input({ required: true }) @Input({ required: true })
context: any; context: any;
@@ -64,11 +67,6 @@ export class LibraryNameColumnComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(
private element: ElementRef,
private nodesApiService: NodesApiService
) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
@@ -35,6 +35,8 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
host: { class: 'adf-library-role-column adf-datatable-content-cell' } host: { class: 'adf-library-role-column adf-datatable-content-cell' }
}) })
export class LibraryRoleColumnComponent implements OnInit { export class LibraryRoleColumnComponent implements OnInit {
private readonly nodesApiService = inject(NodesApiService);
@Input({ required: true }) @Input({ required: true })
context: any; context: any;
@@ -58,8 +60,6 @@ export class LibraryRoleColumnComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(private nodesApiService: NodesApiService) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
@@ -35,6 +35,8 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
host: { class: 'adf-library-status-column adf-datatable-content-cell' } host: { class: 'adf-library-status-column adf-datatable-content-cell' }
}) })
export class LibraryStatusColumnComponent implements OnInit { export class LibraryStatusColumnComponent implements OnInit {
private readonly nodesApiService = inject(NodesApiService);
@Input({ required: true }) @Input({ required: true })
context: any; context: any;
@@ -42,8 +44,6 @@ export class LibraryStatusColumnComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(private nodesApiService: NodesApiService) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
@@ -52,6 +52,9 @@ import { NodeTooltipUtils } from '../../utils/node-tooltip.utils';
host: { class: 'adf-datatable-content-cell adf-datatable-link adf-name-column' } host: { class: 'adf-datatable-content-cell adf-datatable-link adf-name-column' }
}) })
export class NameColumnComponent implements OnInit { export class NameColumnComponent implements OnInit {
private readonly element = inject(ElementRef);
private readonly nodesApiService = inject(NodesApiService);
@Input({ required: true }) @Input({ required: true })
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
context: any; context: any;
@@ -66,11 +69,6 @@ export class NameColumnComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(
private element: ElementRef,
private nodesApiService: NodesApiService
) {}
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
@@ -41,10 +41,10 @@ export class ShareDataRow implements DataRow {
constructor( constructor(
private obj: NodeEntry, private obj: NodeEntry,
private contentService: ContentService, private readonly contentService: ContentService,
private permissionsStyle: PermissionStyleModel[], private readonly permissionsStyle: PermissionStyleModel[],
private thumbnailService?: ThumbnailService, private readonly thumbnailService?: ThumbnailService,
private allowDropFiles?: boolean private readonly allowDropFiles?: boolean
) { ) {
if (!obj) { if (!obj) {
throw new Error(ERR_OBJECT_NOT_FOUND); throw new Error(ERR_OBJECT_NOT_FOUND);
@@ -53,8 +53,8 @@ export class ShareDataTableAdapter implements DataTableAdapter {
} }
constructor( constructor(
private thumbnailService: ThumbnailService, private readonly thumbnailService: ThumbnailService,
private contentService: ContentService, private readonly contentService: ContentService,
schema: DataColumn[] = [], schema: DataColumn[] = [],
sorting?: DataSorting, sorting?: DataSorting,
sortingMode: string = 'client', sortingMode: string = 'client',
@@ -35,7 +35,7 @@ import {
ResultSetPaging, ResultSetPaging,
SEARCH_LANGUAGE SEARCH_LANGUAGE
} from '@alfresco/js-api'; } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Observable, from, of } from 'rxjs'; import { Observable, from, of } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
@@ -43,6 +43,8 @@ const CREATE_PERMISSION: string = 'create';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class CustomResourcesService { export class CustomResourcesService {
private readonly apiService = inject(AlfrescoApiService);
private _peopleApi: PeopleApi; private _peopleApi: PeopleApi;
get peopleApi(): PeopleApi { get peopleApi(): PeopleApi {
this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance()); this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance());
@@ -85,8 +87,6 @@ export class CustomResourcesService {
return this._nodesApi; return this._nodesApi;
} }
constructor(private apiService: AlfrescoApiService) {}
/** /**
* Gets files recently accessed by a user. * Gets files recently accessed by a user.
* *
@@ -69,7 +69,12 @@ describe('DocumentActionsService', () => {
const file = new FileNode(); const file = new FileNode();
expect(service.canExecuteAction(file)).toBeTruthy(); expect(service.canExecuteAction(file)).toBeTruthy();
service = new DocumentActionsService(null, null, null); TestBed.resetTestingModule();
TestBed.configureTestingModule({
imports: [NoopAuthModule],
providers: [{ provide: DocumentListService, useValue: null }]
});
service = TestBed.inject(DocumentActionsService);
expect(service.canExecuteAction(file)).toBeFalsy(); expect(service.canExecuteAction(file)).toBeFalsy();
}); });
@@ -17,7 +17,7 @@
import { TranslationService } from '@alfresco/adf-core'; import { TranslationService } from '@alfresco/adf-core';
import { ContentService } from '../../common/services/content.service'; import { ContentService } from '../../common/services/content.service';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { NodeEntry } from '@alfresco/js-api'; import { NodeEntry } from '@alfresco/js-api';
import { Observable, Subject, throwError, of } from 'rxjs'; import { Observable, Subject, throwError, of } from 'rxjs';
import { ContentActionHandler } from '../models/content-action.model'; import { ContentActionHandler } from '../models/content-action.model';
@@ -30,19 +30,19 @@ import { ContentNodeDialogService } from '../../content-node-selector/content-no
providedIn: 'root' providedIn: 'root'
}) })
export class DocumentActionsService { export class DocumentActionsService {
private readonly nodeActionsService = inject(NodeActionsService);
private readonly contentNodeDialogService = inject(ContentNodeDialogService);
private readonly translation = inject(TranslationService);
private readonly documentListService = inject(DocumentListService);
private readonly contentService = inject(ContentService);
permissionEvent = new Subject<PermissionModel>(); permissionEvent = new Subject<PermissionModel>();
error = new Subject<Error>(); error = new Subject<Error>();
success = new Subject<string>(); success = new Subject<string>();
private handlers: { [id: string]: ContentActionHandler } = {}; private handlers: { [id: string]: ContentActionHandler } = {};
constructor( constructor() {
private nodeActionsService: NodeActionsService,
private contentNodeDialogService: ContentNodeDialogService,
private translation: TranslationService,
private documentListService?: DocumentListService,
private contentService?: ContentService
) {
this.setupActionHandlers(); this.setupActionHandlers();
} }
@@ -32,9 +32,9 @@ const ROOT_ID = '-root-';
providedIn: 'root' providedIn: 'root'
}) })
export class DocumentListService implements DocumentListLoader { export class DocumentListService implements DocumentListLoader {
private nodesApiService = inject(NodesApiService); private readonly nodesApiService = inject(NodesApiService);
private apiService = inject(AlfrescoApiService); private readonly apiService = inject(AlfrescoApiService);
private customResourcesService = inject(CustomResourcesService); private readonly customResourcesService = inject(CustomResourcesService);
private _nodesApi: NodesApi; private _nodesApi: NodesApi;
get nodes(): NodesApi { get nodes(): NodesApi {
@@ -42,8 +42,8 @@ export class DocumentListService implements DocumentListLoader {
return this._nodesApi; return this._nodesApi;
} }
private _reload = new Subject<void>(); private readonly _reload = new Subject<void>();
private _resetSelection = new Subject<void>(); private readonly _resetSelection = new Subject<void>();
/** Gets an observable that emits when the document list should be reloaded. */ /** Gets an observable that emits when the document list should be reloaded. */
reload$ = this._reload.asObservable(); reload$ = this._reload.asObservable();
@@ -17,7 +17,7 @@
import { TranslationService } from '@alfresco/adf-core'; import { TranslationService } from '@alfresco/adf-core';
import { ContentService } from '../../common/services/content.service'; import { ContentService } from '../../common/services/content.service';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { NodeEntry } from '@alfresco/js-api'; import { NodeEntry } from '@alfresco/js-api';
import { Observable, Subject, throwError, of } from 'rxjs'; import { Observable, Subject, throwError, of } from 'rxjs';
import { ContentActionHandler } from '../models/content-action.model'; import { ContentActionHandler } from '../models/content-action.model';
@@ -29,18 +29,18 @@ import { NodeActionsService } from './node-actions.service';
providedIn: 'root' providedIn: 'root'
}) })
export class FolderActionsService { export class FolderActionsService {
private readonly nodeActionsService = inject(NodeActionsService);
private readonly documentListService = inject(DocumentListService);
private readonly contentService = inject(ContentService);
private readonly translation = inject(TranslationService);
permissionEvent = new Subject<PermissionModel>(); permissionEvent = new Subject<PermissionModel>();
error = new Subject<Error>(); error = new Subject<Error>();
success = new Subject<string>(); success = new Subject<string>();
private handlers: { [id: string]: ContentActionHandler } = {}; private handlers: { [id: string]: ContentActionHandler } = {};
constructor( constructor() {
private nodeActionsService: NodeActionsService,
private documentListService: DocumentListService,
private contentService: ContentService,
private translation: TranslationService
) {
this.setupActionHandlers(); this.setupActionHandlers();
} }
@@ -20,7 +20,8 @@ import { LockService } from './lock.service';
import { AuthenticationService, RedirectAuthService } from '@alfresco/adf-core'; import { AuthenticationService, RedirectAuthService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { addDays, subDays } from 'date-fns'; import { addDays, subDays } from 'date-fns';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { EMPTY, of } from 'rxjs'; import { EMPTY, of } from 'rxjs';
describe('LockService', () => { describe('LockService', () => {
@@ -33,8 +34,11 @@ describe('LockService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule], providers: [
providers: [{ provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } }] { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } },
provideHttpClient(),
provideHttpClientTesting()
]
}); });
service = TestBed.inject(LockService); service = TestBed.inject(LockService);
authenticationService = TestBed.inject(AuthenticationService); authenticationService = TestBed.inject(AuthenticationService);
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { AuthenticationService } from '@alfresco/adf-core'; import { AuthenticationService } from '@alfresco/adf-core';
import { isAfter } from 'date-fns'; import { isAfter } from 'date-fns';
@@ -24,7 +24,7 @@ import { isAfter } from 'date-fns';
providedIn: 'root' providedIn: 'root'
}) })
export class LockService { export class LockService {
constructor(private authService: AuthenticationService) {} private readonly authService = inject(AuthenticationService);
isLocked(node: Node): boolean { isLocked(node: Node): boolean {
let isLocked = false; let isLocked = false;
@@ -15,15 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable, Output, EventEmitter } from '@angular/core'; import { Injectable, Output, EventEmitter, inject, Injector, runInInjectionContext } from '@angular/core';
import { Node, NodeEntry } from '@alfresco/js-api'; import { Node, NodeEntry } from '@alfresco/js-api';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { switchMap, map } from 'rxjs/operators'; import { switchMap, map } from 'rxjs/operators';
import { DownloadService } from '@alfresco/adf-core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ContentService } from '../../common/services/content.service'; import { ContentService } from '../../common/services/content.service';
import { NodeDownloadDirective } from '../../directives/node-download.directive'; import { NodeDownloadDirective } from '../../directives/node-download.directive';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { DocumentListService } from './document-list.service'; import { DocumentListService } from './document-list.service';
import { ContentNodeDialogService } from '../../content-node-selector/content-node-dialog.service'; import { ContentNodeDialogService } from '../../content-node-selector/content-node-dialog.service';
@@ -34,21 +32,19 @@ import { NodeAction } from '../models/node-action.enum';
}) })
// eslint-disable-next-line @angular-eslint/directive-class-suffix // eslint-disable-next-line @angular-eslint/directive-class-suffix
export class NodeActionsService { export class NodeActionsService {
private readonly contentDialogService = inject(ContentNodeDialogService);
dialogRef = inject(MatDialog);
content = inject(ContentService);
private readonly documentListService = inject(DocumentListService);
private readonly injector = inject(Injector);
@Output() @Output()
error = new EventEmitter<any>(); error = new EventEmitter<any>();
constructor(
private contentDialogService: ContentNodeDialogService,
public dialogRef: MatDialog,
public content: ContentService,
private documentListService?: DocumentListService,
private apiService?: AlfrescoApiService,
private dialog?: MatDialog,
private downloadService?: DownloadService
) {}
downloadNode(node: NodeEntry) { downloadNode(node: NodeEntry) {
new NodeDownloadDirective(this.apiService, this.downloadService, this.dialog).downloadNode(node); runInInjectionContext(this.injector, () => {
new NodeDownloadDirective().downloadNode(node);
});
} }
/** /**
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/no-input-rename */ /* eslint-disable @angular-eslint/no-input-rename */
import { Directive, ElementRef, HostListener, Input, Output, EventEmitter } from '@angular/core'; import { Directive, ElementRef, HostListener, Input, Output, EventEmitter, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { FolderDialogComponent } from '../dialogs/folder/folder.dialog'; import { FolderDialogComponent } from '../dialogs/folder/folder.dialog';
@@ -29,6 +29,10 @@ const DIALOG_WIDTH: number = 400;
selector: '[adf-edit-folder]' selector: '[adf-edit-folder]'
}) })
export class FolderEditDirective { export class FolderEditDirective {
dialogRef = inject(MatDialog);
elementRef = inject(ElementRef);
content = inject(ContentService);
/** Folder node to edit. */ /** Folder node to edit. */
@Input('adf-edit-folder') @Input('adf-edit-folder')
folder: Node; folder: Node;
@@ -53,8 +57,6 @@ export class FolderEditDirective {
} }
} }
constructor(public dialogRef: MatDialog, public elementRef: ElementRef, public content: ContentService) {}
private get dialogConfig() { private get dialogConfig() {
const { folder } = this; const { folder } = this;
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { ContentIncludeQuery, Group, GroupEntry, GroupsApi } from '@alfresco/js-api'; import { ContentIncludeQuery, Group, GroupEntry, GroupsApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { from, Observable } from 'rxjs'; import { from, Observable } from 'rxjs';
@@ -25,14 +25,14 @@ import { map } from 'rxjs/operators';
providedIn: 'root' providedIn: 'root'
}) })
export class GroupService { export class GroupService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _groupsApi: GroupsApi; private _groupsApi: GroupsApi;
get groupsApi(): GroupsApi { get groupsApi(): GroupsApi {
this._groupsApi = this._groupsApi ?? new GroupsApi(this.alfrescoApiService.getInstance()); this._groupsApi = this._groupsApi ?? new GroupsApi(this.alfrescoApiService.getInstance());
return this._groupsApi; return this._groupsApi;
} }
constructor(private alfrescoApiService: AlfrescoApiService) {}
async listAllGroupMembershipsForPerson(personId: string, opts?: any, accumulator = []): Promise<GroupEntry[]> { async listAllGroupMembershipsForPerson(personId: string, opts?: any, accumulator = []): Promise<GroupEntry[]> {
const groupsPaginated = await this.groupsApi.listGroupMembershipsForPerson(personId, opts); const groupsPaginated = await this.groupsApi.listGroupMembershipsForPerson(personId, opts);
accumulator = [...accumulator, ...groupsPaginated.list.entries]; accumulator = [...accumulator, ...groupsPaginated.list.entries];
@@ -22,8 +22,8 @@ import { take, tap } from 'rxjs/operators';
export abstract class InfiniteScrollDatasource<T> extends DataSource<T> { export abstract class InfiniteScrollDatasource<T> extends DataSource<T> {
protected readonly dataStream = new BehaviorSubject<T[]>([]); protected readonly dataStream = new BehaviorSubject<T[]>([]);
private isLoading$ = new Subject<boolean>(); private readonly isLoading$ = new Subject<boolean>();
private subscription = new Subscription(); private readonly subscription = new Subscription();
private batchesFetched = 0; private batchesFetched = 0;
private _itemsCount = 0; private _itemsCount = 0;
private _firstItem: T; private _firstItem: T;
@@ -26,7 +26,7 @@ import {
LegalHoldApi, LegalHoldApi,
RequestQuery RequestQuery
} from '@alfresco/js-api'; } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Observable, from } from 'rxjs'; import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -35,14 +35,14 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
providedIn: 'root' providedIn: 'root'
}) })
export class LegalHoldService { export class LegalHoldService {
private readonly apiService = inject(AlfrescoApiService);
private _legalHoldApi: LegalHoldApi; private _legalHoldApi: LegalHoldApi;
get legalHoldApi(): LegalHoldApi { get legalHoldApi(): LegalHoldApi {
this._legalHoldApi = this._legalHoldApi ?? new LegalHoldApi(this.apiService.getInstance()); this._legalHoldApi = this._legalHoldApi ?? new LegalHoldApi(this.apiService.getInstance());
return this._legalHoldApi; return this._legalHoldApi;
} }
constructor(private readonly apiService: AlfrescoApiService) {}
/** /**
* Gets the list of holds available in the file plan. * Gets the list of holds available in the file plan.
* *
@@ -17,12 +17,12 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
import { AppConfigService, StorageService } from '@alfresco/adf-core';
@Injectable() @Injectable()
export class AlfrescoApiServiceMock extends AlfrescoApiService { export class AlfrescoApiServiceMock extends AlfrescoApiService {
constructor(protected appConfig: AppConfigService, protected storageService: StorageService) { constructor() {
super(appConfig, storageService); super();
if (!this.alfrescoApi) { if (!this.alfrescoApi) {
this.initAlfrescoApi(); this.initAlfrescoApi();
} }
@@ -17,8 +17,6 @@
import { NodeEntry } from '@alfresco/js-api'; import { NodeEntry } from '@alfresco/js-api';
import { of, Observable, ReplaySubject } from 'rxjs'; import { of, Observable, ReplaySubject } from 'rxjs';
import { AlfrescoApiService } from '../services';
import { AuthenticationService } from '@alfresco/adf-core';
import { SavedSearch, SavedSearchesBaseService } from '../common'; import { SavedSearch, SavedSearchesBaseService } from '../common';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
@@ -28,10 +26,6 @@ export class MockSavedSearchesService extends SavedSearchesBaseService {
public updateSpy = jasmine.createSpy('updateSavedSearches').and.returnValue(of({} as NodeEntry)); public updateSpy = jasmine.createSpy('updateSavedSearches').and.returnValue(of({} as NodeEntry));
constructor(apiService: AlfrescoApiService, authService: AuthenticationService) {
super(apiService, authService);
}
protected fetchAllSavedSearches(): Observable<SavedSearch[]> { protected fetchAllSavedSearches(): Observable<SavedSearch[]> {
return this.fetchSubject.asObservable(); return this.fetchSubject.asObservable();
} }
@@ -16,7 +16,7 @@
*/ */
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { Component, EventEmitter, Inject, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, OnInit, Output, ViewEncapsulation, inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { NewVersionUploaderDialogData, NewVersionUploaderData, NewVersionUploaderDataAction } from './models'; import { NewVersionUploaderDialogData, NewVersionUploaderData, NewVersionUploaderDataAction } from './models';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@@ -45,6 +45,9 @@ import { VersionListComponent } from '../version-manager/version-list.component'
} }
}) })
export class NewVersionUploaderDialogComponent implements OnInit { export class NewVersionUploaderDialogComponent implements OnInit {
data = inject<NewVersionUploaderDialogData>(MAT_DIALOG_DATA);
private readonly dialogRef = inject<MatDialogRef<NewVersionUploaderDialogComponent>>(MatDialogRef);
/** /**
* Dialog title to show into the header. * Dialog title to show into the header.
* If data.title is not provided, a default title is set * If data.title is not provided, a default title is set
@@ -59,11 +62,6 @@ export class NewVersionUploaderDialogComponent implements OnInit {
@Output() @Output()
uploadError = new EventEmitter<any>(); uploadError = new EventEmitter<any>();
constructor(
@Inject(MAT_DIALOG_DATA) public data: NewVersionUploaderDialogData,
private dialogRef: MatDialogRef<NewVersionUploaderDialogComponent>
) {}
ngOnInit(): void { ngOnInit(): void {
this.setDialogTitle(); this.setDialogTitle();
} }
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { AlfrescoApiService } from '../services/alfresco-api.service'; import { AlfrescoApiService } from '../services/alfresco-api.service';
@@ -30,14 +30,16 @@ import { take } from 'rxjs/operators';
providedIn: 'root' providedIn: 'root'
}) })
export class NewVersionUploaderService { export class NewVersionUploaderService {
private readonly apiService = inject(AlfrescoApiService);
private readonly dialog = inject(MatDialog);
private readonly overlayContainer = inject(OverlayContainer);
private _versionsApi: VersionsApi; private _versionsApi: VersionsApi;
get versionsApi(): VersionsApi { get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance()); this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
return this._versionsApi; return this._versionsApi;
} }
constructor(private apiService: AlfrescoApiService, private dialog: MatDialog, private overlayContainer: OverlayContainer) {}
/** /**
* Open a dialog NewVersionUploaderDialogComponent to display: * Open a dialog NewVersionUploaderDialogComponent to display:
* - a side by side comparison between the current target node (type, name, icon) and the new file that should update it's version * - a side by side comparison between the current target node (type, name, icon) and the new file that should update it's version
@@ -19,7 +19,8 @@ import { TestBed } from '@angular/core/testing';
import { CommentModel, RedirectAuthService } from '@alfresco/adf-core'; import { CommentModel, RedirectAuthService } from '@alfresco/adf-core';
import { fakeContentComment, fakeContentComments } from '../mocks/node-comments.mock'; import { fakeContentComment, fakeContentComments } from '../mocks/node-comments.mock';
import { NodeCommentsService } from './node-comments.service'; import { NodeCommentsService } from './node-comments.service';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { EMPTY, of } from 'rxjs'; import { EMPTY, of } from 'rxjs';
import { AlfrescoApiService } from '../../services'; import { AlfrescoApiService } from '../../services';
import { AlfrescoApiServiceMock } from '../../mock'; import { AlfrescoApiServiceMock } from '../../mock';
@@ -31,10 +32,11 @@ describe('NodeCommentsService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
{ provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } } { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } },
provideHttpClient(),
provideHttpClientTesting()
] ]
}); });
service = TestBed.inject(NodeCommentsService); service = TestBed.inject(NodeCommentsService);
@@ -17,7 +17,7 @@
import { CommentModel, CommentsService, User } from '@alfresco/adf-core'; import { CommentModel, CommentsService, User } from '@alfresco/adf-core';
import { CommentEntry, CommentsApi, Comment, PeopleApi } from '@alfresco/js-api'; import { CommentEntry, CommentsApi, Comment, PeopleApi } from '@alfresco/js-api';
import { Injectable } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { Observable, from } from 'rxjs'; import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -26,6 +26,8 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
providedIn: 'root' providedIn: 'root'
}) })
export class NodeCommentsService implements CommentsService { export class NodeCommentsService implements CommentsService {
private readonly apiService = inject(AlfrescoApiService);
private _commentsApi: CommentsApi; private _commentsApi: CommentsApi;
get commentsApi(): CommentsApi { get commentsApi(): CommentsApi {
this._commentsApi = this._commentsApi ?? new CommentsApi(this.apiService.getInstance()); this._commentsApi = this._commentsApi ?? new CommentsApi(this.apiService.getInstance());
@@ -38,8 +40,6 @@ export class NodeCommentsService implements CommentsService {
return this._peopleApi; return this._peopleApi;
} }
constructor(private readonly apiService: AlfrescoApiService) {}
/** /**
* Gets all comments that have been added to a task. * Gets all comments that have been added to a task.
* *
@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, Inject, ViewEncapsulation } from '@angular/core'; import { Component, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { NodeEntry, PermissionElement } from '@alfresco/js-api'; import { NodeEntry, PermissionElement } from '@alfresco/js-api';
import { AddPermissionDialogData } from './add-permission-dialog-data.interface'; import { AddPermissionDialogData } from './add-permission-dialog-data.interface';
@@ -51,16 +51,16 @@ import { UserRoleColumnComponent } from '../user-role-column/user-role-column.co
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AddPermissionDialogComponent { export class AddPermissionDialogComponent {
data = inject<AddPermissionDialogData>(MAT_DIALOG_DATA);
private readonly dialogRef = inject<MatDialogRef<AddPermissionDialogComponent>>(MatDialogRef);
isSearchActive = true; isSearchActive = true;
selectedMembers: MemberModel[] = []; selectedMembers: MemberModel[] = [];
private existingMembers: PermissionElement[] = []; private readonly existingMembers: PermissionElement[] = [];
currentSelection: NodeEntry[] = []; currentSelection: NodeEntry[] = [];
constructor( constructor() {
@Inject(MAT_DIALOG_DATA) public data: AddPermissionDialogData,
private dialogRef: MatDialogRef<AddPermissionDialogComponent>
) {
this.existingMembers = this.data.node.permissions.locallySet || []; this.existingMembers = this.data.node.permissions.locallySet || [];
} }
@@ -16,7 +16,7 @@
*/ */
import { Node, NodeEntry, PermissionElement } from '@alfresco/js-api'; import { Node, NodeEntry, PermissionElement } from '@alfresco/js-api';
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation, inject } from '@angular/core';
import { NodePermissionService } from '../../services/node-permission.service'; import { NodePermissionService } from '../../services/node-permission.service';
import { RoleModel } from '../../models/role.model'; import { RoleModel } from '../../models/role.model';
import { ContentService } from '../../../common/services/content.service'; import { ContentService } from '../../../common/services/content.service';
@@ -37,6 +37,9 @@ import { TranslatePipe } from '@ngx-translate/core';
* @deprecated in 4.4.0, use adf-add-permission-panel instead. * @deprecated in 4.4.0, use adf-add-permission-panel instead.
*/ */
export class AddPermissionComponent implements OnInit { export class AddPermissionComponent implements OnInit {
private readonly nodePermissionService = inject(NodePermissionService);
private readonly contentService = inject(ContentService);
/** ID of the target node. */ /** ID of the target node. */
@Input({ required: true }) @Input({ required: true })
nodeId: string; nodeId: string;
@@ -53,8 +56,6 @@ export class AddPermissionComponent implements OnInit {
currentNode: Node; currentNode: Node;
currentNodeRoles: RoleModel[]; currentNodeRoles: RoleModel[];
constructor(private nodePermissionService: NodePermissionService, private contentService: ContentService) {}
ngOnInit(): void { ngOnInit(): void {
this.nodePermissionService.getNodeWithRoles(this.nodeId).subscribe(({ node, roles }) => { this.nodePermissionService.getNodeWithRoles(this.nodeId).subscribe(({ node, roles }) => {
this.currentNode = node; this.currentNode = node;
@@ -16,7 +16,7 @@
*/ */
import { SearchRequest } from '@alfresco/js-api'; import { SearchRequest } from '@alfresco/js-api';
import { Injectable, Optional, Inject, InjectionToken } from '@angular/core'; import { Injectable, InjectionToken, inject } from '@angular/core';
import { SearchConfigurationInterface } from '../../../common/interfaces/search-configuration.interface'; import { SearchConfigurationInterface } from '../../../common/interfaces/search-configuration.interface';
export const SEARCH_QUERY_TOKEN = new InjectionToken<QueryProvider>('Alfresco Search Query Token'); export const SEARCH_QUERY_TOKEN = new InjectionToken<QueryProvider>('Alfresco Search Query Token');
@@ -26,11 +26,7 @@ export interface QueryProvider {
@Injectable() @Injectable()
export class SearchPermissionConfigurationService implements SearchConfigurationInterface { export class SearchPermissionConfigurationService implements SearchConfigurationInterface {
constructor( private readonly queryProvider = inject<QueryProvider>(SEARCH_QUERY_TOKEN, { optional: true });
@Optional()
@Inject(SEARCH_QUERY_TOKEN)
private queryProvider: QueryProvider
) {}
public generateQueryBody(searchTerm: string, maxResults: number, skipCount: number): SearchRequest { public generateQueryBody(searchTerm: string, maxResults: number, skipCount: number): SearchRequest {
return { return {
@@ -16,7 +16,7 @@
*/ */
/* eslint-disable @angular-eslint/no-input-rename */ /* eslint-disable @angular-eslint/no-input-rename */
import { Directive, Input, Output, EventEmitter } from '@angular/core'; import { Directive, Input, Output, EventEmitter, inject } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { ContentService } from '../../common/services/content.service'; import { ContentService } from '../../common/services/content.service';
import { NodesApiService } from '../../common/services/nodes-api.service'; import { NodesApiService } from '../../common/services/nodes-api.service';
@@ -30,6 +30,9 @@ import { AllowableOperationsEnum } from '../../common/models/allowable-operation
} }
}) })
export class InheritPermissionDirective { export class InheritPermissionDirective {
private readonly nodeService = inject(NodesApiService);
private readonly contentService = inject(ContentService);
/** ID of the node to add/remove inherited permissions. */ /** ID of the node to add/remove inherited permissions. */
@Input() @Input()
nodeId: string; nodeId: string;
@@ -42,8 +45,6 @@ export class InheritPermissionDirective {
@Output() @Output()
error: EventEmitter<any> = new EventEmitter<any>(); error: EventEmitter<any> = new EventEmitter<any>();
constructor(private nodeService: NodesApiService, private contentService: ContentService) {}
onInheritPermissionClicked() { onInheritPermissionClicked() {
this.nodeService.getNode(this.nodeId).subscribe((node: Node) => { this.nodeService.getNode(this.nodeId).subscribe((node: Node) => {
if (this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.UPDATEPERMISSIONS)) { if (this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.UPDATEPERMISSIONS)) {

Some files were not shown because too many files have changed in this diff Show More