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
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation, inject } from '@angular/core';
import { LicenseData } from '../interfaces';
import { CommonModule } from '@angular/common';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
@@ -30,6 +30,8 @@ import { MatTableModule } from '@angular/material/table';
imports: [CommonModule, TranslatePipe, MatTableModule]
})
export class AboutLicenseListComponent {
private readonly translateService = inject(TranslateService);
columns = [
{
columnDef: 'property',
@@ -64,6 +66,4 @@ export class AboutLicenseListComponent {
@Input({ required: true })
data: LicenseData[] = [];
constructor(private readonly translateService: TranslateService) {}
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
@@ -29,11 +29,11 @@ import { MatCardModule } from '@angular/material/card';
imports: [CommonModule, TranslatePipe, MatCardModule]
})
export class AboutServerSettingsComponent implements OnInit {
private readonly appConfig = inject(AppConfigService);
ecmHost = '';
bpmHost = '';
constructor(private appConfig: AppConfigService) {}
ngOnInit() {
this.ecmHost = this.appConfig.get(AppConfigValues.ECMHOST);
this.bpmHost = this.appConfig.get(AppConfigValues.BPMHOST);
@@ -30,7 +30,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
})
export class AppExtensionServiceMock {
references$: Observable<ExtensionRef[]>;
private _references = new BehaviorSubject<ExtensionRef[]>([]);
private readonly _references = new BehaviorSubject<ExtensionRef[]>([]);
constructor() {
this.references$ = this._references.asObservable();
@@ -16,8 +16,10 @@
*/
import { of } from 'rxjs';
import { StoragePrefixFactory, StoragePrefixFactoryService } from './app-config-storage-prefix.factory';
import { StoragePrefixFactory, StoragePrefixFactoryService, STORAGE_PREFIX_FACTORY_SERVICE } from './app-config-storage-prefix.factory';
import { AppConfigService } from './app-config.service';
import { Injector, runInInjectionContext } from '@angular/core';
import { TestBed } from '@angular/core/testing';
type TestAppConfigService = Pick<AppConfigService, 'select'>;
@@ -31,7 +33,12 @@ describe('StoragePrefixFactory', () => {
}
};
const prefixFactory = new StoragePrefixFactory(appConfigService as AppConfigService);
const injector = Injector.create({
providers: [{ provide: AppConfigService, useValue: appConfigService }],
parent: TestBed.inject(Injector)
});
const prefixFactory = runInInjectionContext(injector, () => new StoragePrefixFactory());
prefixFactory.getPrefix().subscribe((prefix) => {
expect(prefix).toBe(appConfigPrefix);
@@ -47,7 +54,12 @@ describe('StoragePrefixFactory', () => {
}
};
const prefixFactory = new StoragePrefixFactory(appConfigService as AppConfigService);
const injector = Injector.create({
providers: [{ provide: AppConfigService, useValue: appConfigService }],
parent: TestBed.inject(Injector)
});
const prefixFactory = runInInjectionContext(injector, () => new StoragePrefixFactory());
prefixFactory.getPrefix().subscribe((prefix) => {
expect(prefix).toBe(appConfigPrefix);
@@ -69,7 +81,15 @@ describe('StoragePrefixFactory', () => {
}
};
const prefixFactory = new StoragePrefixFactory(appConfigService as AppConfigService, externalPrefixFactory);
const injector = Injector.create({
providers: [
{ provide: AppConfigService, useValue: appConfigService },
{ provide: STORAGE_PREFIX_FACTORY_SERVICE, useValue: externalPrefixFactory }
],
parent: TestBed.inject(Injector)
});
const prefixFactory = runInInjectionContext(injector, () => new StoragePrefixFactory());
prefixFactory.getPrefix().subscribe((prefix) => {
expect(prefix).toBe('prefix-from-factory');
@@ -92,7 +112,15 @@ describe('StoragePrefixFactory', () => {
}
};
const prefixFactory = new StoragePrefixFactory(appConfigService as AppConfigService, externalPrefixFactory);
const injector = Injector.create({
providers: [
{ provide: AppConfigService, useValue: appConfigService },
{ provide: STORAGE_PREFIX_FACTORY_SERVICE, useValue: externalPrefixFactory }
],
parent: TestBed.inject(Injector)
});
const prefixFactory = runInInjectionContext(injector, () => new StoragePrefixFactory());
prefixFactory.getPrefix().subscribe((prefix) => {
expect(prefix).toBe(appConfigPrefix);
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Inject, Injectable, InjectionToken, Optional } from '@angular/core';
import { Injectable, InjectionToken, inject } from '@angular/core';
import { AppConfigService, AppConfigValues } from './app-config.service';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
@@ -30,12 +30,8 @@ export const STORAGE_PREFIX_FACTORY_SERVICE = new InjectionToken<StoragePrefixFa
providedIn: 'root'
})
export class StoragePrefixFactory {
constructor(
private appConfigService: AppConfigService,
@Optional()
@Inject(STORAGE_PREFIX_FACTORY_SERVICE)
private storagePrefixFactory?: StoragePrefixFactoryService
) {}
private readonly appConfigService = inject(AppConfigService);
private readonly storagePrefixFactory = inject<StoragePrefixFactoryService>(STORAGE_PREFIX_FACTORY_SERVICE, { optional: true });
getPrefix(): Observable<string | undefined> {
return this.appConfigService.select(AppConfigValues.STORAGE_PREFIX).pipe(
@@ -15,14 +15,14 @@
* limitations under the License.
*/
import { Pipe, PipeTransform } from '@angular/core';
import { Pipe, PipeTransform, inject } from '@angular/core';
import { AppConfigService } from './app-config.service';
@Pipe({
name: 'adfAppConfig'
})
export class AppConfigPipe implements PipeTransform {
constructor(private config: AppConfigService) {}
private readonly config = inject(AppConfigService);
transform(value: string, fallback?: any): any {
return this.config.get(value, fallback);
@@ -16,7 +16,7 @@
*/
import { throwError as observableThrowError, Observable } from 'rxjs';
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import {
HttpHandler,
HttpInterceptor,
@@ -33,12 +33,12 @@ import { AuthenticationService } from '../services/authentication.service';
@Injectable()
export class AuthBearerInterceptor implements HttpInterceptor {
private _bearerExcludedUrls: readonly string[] = ['resources/', 'assets/', 'auth/realms', 'idp/'];
private readonly authenticationService = inject(AuthenticationService);
private readonly _bearerExcludedUrls: readonly string[] = ['resources/', 'assets/', 'auth/realms', 'idp/'];
private excludedUrlsRegex: RegExp[];
constructor(private authenticationService: AuthenticationService) {}
private loadExcludedUrlsRegex() {
const excludedUrls = this.bearerExcludedUrls;
this.excludedUrlsRegex = excludedUrls.map((urlPattern) => new RegExp(`^https?://[^/]+/${urlPattern}`, 'i')) || [];
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { Authentication } from '../interfaces/authentication.interface';
import { CookieService } from '../../common/services/cookie.service';
@@ -34,6 +34,9 @@ const REMEMBER_ME_UNTIL = 1000 * 60 * 60 * 24 * 30;
providedIn: 'root'
})
export class BasicAlfrescoAuthService extends BaseAuthenticationService {
private readonly contentAuth = inject(ContentAuth);
private readonly processAuth = inject(ProcessAuth);
protected redirectUrl: RedirectionModel = null;
authentications: Authentication = {
@@ -43,12 +46,10 @@ export class BasicAlfrescoAuthService extends BaseAuthenticationService {
type: 'basic'
};
constructor(
appConfig: AppConfigService,
cookie: CookieService,
private readonly contentAuth: ContentAuth,
private readonly processAuth: ProcessAuth
) {
constructor() {
const appConfig = inject(AppConfigService);
const cookie = inject(CookieService);
super(appConfig, cookie);
this.appConfig.onLoad.subscribe(() => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { AdfHttpClient } from '@alfresco/adf-core/api';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { StorageService } from '../../common/services/storage.service';
@@ -38,6 +38,10 @@ export interface TicketEntry {
providedIn: 'root'
})
export class ContentAuth {
private readonly appConfigService = inject(AppConfigService);
private readonly adfHttpClient = inject(AdfHttpClient);
private readonly storageService = inject(StorageService);
onLogin = new ReplaySubject<any>(1);
onLogout = new ReplaySubject<any>(1);
onError = new Subject<any>();
@@ -59,7 +63,7 @@ export class ContentAuth {
return this.appConfigService.get<string>(AppConfigValues.ECMHOST) + '/' + contextRootEcm + '/api/-default-/public/authentication/versions/1';
}
constructor(private appConfigService: AppConfigService, private adfHttpClient: AdfHttpClient, private storageService: StorageService) {
constructor() {
this.appConfigService.onLoad.subscribe(() => {
this.setConfig();
});
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { AdfHttpClient } from '@alfresco/adf-core/api';
import { Authentication } from '../interfaces/authentication.interface';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
@@ -26,6 +26,10 @@ import { ReplaySubject, Subject } from 'rxjs';
providedIn: 'root'
})
export class ProcessAuth {
private readonly appConfigService = inject(AppConfigService);
private readonly adfHttpClient = inject(AdfHttpClient);
private readonly storageService = inject(StorageService);
onLogin = new ReplaySubject<any>(1);
onLogout = new ReplaySubject<any>(1);
onError = new Subject<any>();
@@ -45,7 +49,7 @@ export class ProcessAuth {
return this.appConfigService.get<string>(AppConfigValues.BPMHOST) + '/' + contextRootBpm;
}
constructor(private appConfigService: AppConfigService, private adfHttpClient: AdfHttpClient, private storageService: StorageService) {
constructor() {
this.appConfigService.onLoad.subscribe(() => {
this.setConfig();
});
@@ -23,21 +23,19 @@ import { MatDialog } from '@angular/material/dialog';
import { StorageService } from '../../common/services/storage.service';
import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.service';
import { OidcAuthenticationService } from '../oidc/oidc-authentication.service';
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AuthGuardService {
constructor(
private authenticationService: AuthenticationService,
private basicAlfrescoAuthService: BasicAlfrescoAuthService,
private oidcAuthenticationService: OidcAuthenticationService,
private router: Router,
private appConfigService: AppConfigService,
private dialog: MatDialog,
private storageService: StorageService
) {}
private readonly authenticationService = inject(AuthenticationService);
private readonly basicAlfrescoAuthService = inject(BasicAlfrescoAuthService);
private readonly oidcAuthenticationService = inject(OidcAuthenticationService);
private readonly router = inject(Router);
private readonly appConfigService = inject(AppConfigService);
private readonly dialog = inject(MatDialog);
private readonly storageService = inject(StorageService);
get withCredentials(): boolean {
return this.appConfigService.get<boolean>('auth.withCredentials', false);
@@ -15,7 +15,8 @@
* limitations under the License.
*/
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { AppConfigService } from '../../app-config/app-config.service';
@@ -90,8 +91,7 @@ describe('AuthConfigService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [{ provide: AUTH_MODULE_CONFIG, useValue: { useHash: true } }]
providers: [{ provide: AUTH_MODULE_CONFIG, useValue: { useHash: true } }, provideHttpClient(), provideHttpClientTesting()]
});
service = TestBed.inject(AuthConfigService);
spyOn<any>(service, 'getLocationOrigin').and.returnValue('http://localhost:3000');
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Inject, Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { AuthConfig } from 'angular-oauth2-oidc';
import { take } from 'rxjs/operators';
import { AppConfigService } from '../../app-config/app-config.service';
@@ -37,12 +37,10 @@ export function authConfigFactory(authConfigService: AuthConfigService): Promise
providedIn: 'root'
})
export class AuthConfigService {
constructor(
private appConfigService: AppConfigService,
@Inject(AUTH_MODULE_CONFIG) private readonly authModuleConfig: AuthModuleConfig
) {}
private readonly appConfigService = inject(AppConfigService);
private readonly authModuleConfig = inject<AuthModuleConfig>(AUTH_MODULE_CONFIG);
private _authConfig!: AuthConfig;
private readonly _authConfig!: AuthConfig;
get authConfig(): AuthConfig {
return this._authConfig;
}
@@ -33,6 +33,11 @@ import { HttpHeaders } from '@angular/common/http';
providedIn: 'root'
})
export class OidcAuthenticationService extends BaseAuthenticationService {
private readonly jwtHelperService = inject(JwtHelperService);
private readonly authStorage = inject(OAuthStorage);
private readonly oauthService = inject(OAuthService);
private readonly authConfig = inject(AuthConfigService);
private readonly auth = inject(AuthService);
/**
@@ -46,14 +51,10 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
map(([authenticated, isDiscoveryDocumentLoaded]) => !authenticated && isDiscoveryDocumentLoaded)
);
constructor(
appConfig: AppConfigService,
cookie: CookieService,
private jwtHelperService: JwtHelperService,
private authStorage: OAuthStorage,
private oauthService: OAuthService,
private readonly authConfig: AuthConfigService
) {
constructor() {
const appConfig = inject(AppConfigService);
const cookie = inject(CookieService);
super(appConfig, cookie);
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Inject, Injectable, inject } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import {
AuthConfig,
AUTH_CONFIG,
@@ -40,12 +40,15 @@ const isPromise = <T>(value: T | Promise<T>): value is Promise<T> => value && ty
@Injectable()
export class RedirectAuthService extends AuthService {
private readonly oauthService = inject(OAuthService);
private readonly _oauthStorage = inject(OAuthStorage);
readonly authModuleConfig: AuthModuleConfig = inject(AUTH_MODULE_CONFIG);
private readonly _retryLoginService: RetryLoginService = inject(RetryLoginService);
private readonly _oauthLogger: OAuthLogger = inject(OAuthLogger);
private readonly _timeSyncService: TimeSyncService = inject(TimeSyncService);
private _isDiscoveryDocumentLoadedSubject$ = new ReplaySubject<boolean>();
private readonly _isDiscoveryDocumentLoadedSubject$ = new ReplaySubject<boolean>();
public isDiscoveryDocumentLoaded$ = this._isDiscoveryDocumentLoadedSubject$.asObservable();
onLogin: Observable<any>;
@@ -119,7 +122,7 @@ export class RedirectAuthService extends AuthService {
return this.oauthService.hasValidIdToken() && this.oauthService.hasValidAccessToken();
}
private authConfig!: AuthConfig | Promise<AuthConfig>;
private readonly authConfig!: AuthConfig | Promise<AuthConfig>;
private readonly AUTH_STORAGE_ITEMS: string[] = [
'access_token',
@@ -136,8 +139,11 @@ export class RedirectAuthService extends AuthService {
'session_state'
];
constructor(private oauthService: OAuthService, private _oauthStorage: OAuthStorage, @Inject(AUTH_CONFIG) authConfig: AuthConfig) {
constructor() {
const authConfig = inject<AuthConfig>(AUTH_CONFIG);
super();
const oauthService = this.oauthService;
this.authConfig = authConfig;
@@ -22,7 +22,7 @@ import { LoginOptions, OAuthErrorEvent, OAuthService } from 'angular-oauth2-oidc
providedIn: 'root'
})
export class RetryLoginService {
private oauthService = inject(OAuthService);
private readonly oauthService = inject(OAuthService);
/**
* Attempts to log in a specified number of times if the initial login attempt fails.
@@ -15,8 +15,8 @@
* limitations under the License.
*/
import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { HTTP_INTERCEPTORS, HttpClient, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
import { TokenInterceptor } from './token.interceptor';
@@ -38,7 +38,6 @@ describe('TokenInterceptor', () => {
};
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{ provide: OAuthService, useValue: oauthServiceMock },
{ provide: OAuthStorage, useValue: oauthStorageMock },
@@ -46,7 +45,9 @@ describe('TokenInterceptor', () => {
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
},
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting()
]
});
@@ -18,6 +18,7 @@
import { TestBed } from '@angular/core/testing';
import { AuthenticationService } from './authentication.service';
import { CookieService } from '../../common/services/cookie.service';
import { Injector, runInInjectionContext } from '@angular/core';
import { AppConfigService } from '../../app-config/app-config.service';
import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.service';
import { provideCoreAuth } from '../oidc/auth.module';
@@ -28,7 +29,6 @@ import { OidcAuthenticationService } from '../oidc/oidc-authentication.service';
import { OAuthEvent } from 'angular-oauth2-oidc';
import { firstValueFrom, of, Subject, throwError } from 'rxjs';
import { RedirectAuthService } from '../oidc/redirect-auth.service';
import { Injector } from '@angular/core';
import { ContentAuth, ProcessAuth } from '../public-api';
declare let jasmine: any;
@@ -335,8 +335,15 @@ describe('AuthenticationService', () => {
redirectAuthService = TestBed.inject(RedirectAuthService);
redirectAuthService.onTokenReceived = onTokenReceived$;
const injector = TestBed.inject(Injector);
authenticationService = new AuthenticationService(injector, redirectAuthService);
const injector = Injector.create({
providers: [
{ provide: Injector, useValue: TestBed.inject(Injector) },
{ provide: RedirectAuthService, useValue: redirectAuthService }
],
parent: TestBed.inject(Injector)
});
authenticationService = runInInjectionContext(injector, () => new AuthenticationService());
});
it('should emit event when RedirectAuthService onTokenReceived emits', () => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable, Injector } from '@angular/core';
import { Injectable, Injector, inject } from '@angular/core';
import { OidcAuthenticationService } from '../oidc/oidc-authentication.service';
import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.service';
import { Observable, Subject, from } from 'rxjs';
@@ -28,14 +28,14 @@ type EventEmitterInstance = InstanceType<typeof EventEmitter>;
providedIn: 'root'
})
export class AuthenticationService implements AuthenticationServiceInterface {
private readonly injector = inject(Injector);
private readonly redirectAuthService = inject(RedirectAuthService);
onLogin: Subject<any> = new Subject<any>();
onLogout: Subject<any> = new Subject<any>();
onTokenReceived: Subject<any> = new Subject<any>();
constructor(
private readonly injector: Injector,
private readonly redirectAuthService: RedirectAuthService
) {
constructor() {
this.redirectAuthService.onLogin.subscribe((value) => this.onLogin.next(value));
this.redirectAuthService.onTokenReceived.subscribe((value) => this.onTokenReceived.next(value));
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { AppConfigService } from '../../app-config/app-config.service';
@@ -32,7 +32,8 @@ import { OAuth2Service } from './oauth2.service';
@Injectable({ providedIn: 'root' })
export class IdentityGroupService implements IdentityGroupServiceInterface {
constructor(private oAuth2Service: OAuth2Service, private appConfigService: AppConfigService) {}
private readonly oAuth2Service = inject(OAuth2Service);
private readonly appConfigService = inject(AppConfigService);
private get identityHost(): string {
return `${this.appConfigService.get('identityHost')}`;
@@ -133,7 +134,7 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
hasMoreItems: false,
totalItems: totalCount.count
}
} as IdentityGroupQueryResponse)
}) as IdentityGroupQueryResponse
)
)
)
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -32,10 +32,13 @@ export interface IdentityRoleResponseModel {
providedIn: 'root'
})
export class IdentityRoleService {
protected http = inject(HttpClient);
protected appConfig = inject(AppConfigService);
contextRoot = '';
identityHost = '';
constructor(protected http: HttpClient, protected appConfig: AppConfigService) {
constructor() {
this.contextRoot = this.appConfig.get('apiHost', '');
this.identityHost = this.appConfig.get('identityHost');
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { firstValueFrom, Observable, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { AppConfigService } from '../../app-config/app-config.service';
@@ -36,11 +36,9 @@ import { OAuth2Service } from './oauth2.service';
providedIn: 'root'
})
export class IdentityUserService implements IdentityUserServiceInterface {
constructor(
private jwtHelperService: JwtHelperService,
private oAuth2Service: OAuth2Service,
private appConfigService: AppConfigService
) {}
private readonly jwtHelperService = inject(JwtHelperService);
private readonly oAuth2Service = inject(OAuth2Service);
private readonly appConfigService = inject(AppConfigService);
private get identityHost(): string {
return `${this.appConfigService.get('identityHost')}`;
@@ -33,7 +33,7 @@ export class JwtHelperService {
static USER_PREFERRED_USERNAME = 'preferred_username';
static HXP_AUTHORIZATION = 'hxp_authorization';
private storageService: OAuthStorage = inject(OAuthStorage);
private readonly storageService: OAuthStorage = inject(OAuthStorage);
/**
* Decodes a JSON web token into a JS object.
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Observable, from } from 'rxjs';
import { AdfHttpClient } from '@alfresco/adf-core/api';
@@ -31,7 +31,7 @@ export interface OAuth2RequestParams {
@Injectable({ providedIn: 'root' })
export class OAuth2Service {
constructor(private adfHttpClient: AdfHttpClient) {}
private readonly adfHttpClient = inject(AdfHttpClient);
request<T>(opts: OAuth2RequestParams): Observable<T> {
const { httpMethod, url, bodyParam, queryParams } = opts;
@@ -15,7 +15,8 @@
* limitations under the License.
*/
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { AppConfigService } from '../../app-config/app-config.service';
import { TimeSyncService } from './time-sync.service';
@@ -30,8 +31,7 @@ describe('TimeSyncService', () => {
appConfigSpy = jasmine.createSpyObj('AppConfigService', ['get']);
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [TimeSyncService, { provide: AppConfigService, useValue: appConfigSpy }]
providers: [TimeSyncService, { provide: AppConfigService, useValue: appConfigSpy }, provideHttpClient(), provideHttpClientTesting()]
});
service = TestBed.inject(TimeSyncService);
@@ -16,7 +16,7 @@
*/
import { HttpClient } from '@angular/common/http';
import { Injectable, Injector } from '@angular/core';
import { Injectable, Injector, inject } from '@angular/core';
import { AppConfigService } from '../../app-config/app-config.service';
import { from, Observable, throwError } from 'rxjs';
import { catchError, map, timeout } from 'rxjs/operators';
@@ -32,9 +32,12 @@ export interface TimeSync {
providedIn: 'root'
})
export class TimeSyncService {
private readonly _injector = inject(Injector);
private readonly _appConfigService = inject(AppConfigService);
private readonly _http: HttpClient;
constructor(private _injector: Injector, private _appConfigService: AppConfigService) {
constructor() {
this._http = this._injector.get(HttpClient);
}
@@ -19,7 +19,8 @@ import { TestBed } from '@angular/core/testing';
import { UserAccessService } from './user-access.service';
import { JwtHelperService } from './jwt-helper.service';
import { AppConfigService } from '../../app-config';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { JWT_STORAGE_SERVICE, provideCoreAuth } from '../oidc/auth.module';
import { StorageService } from '../../common/services/storage.service';
@@ -30,8 +31,12 @@ describe('UserAccessService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [provideCoreAuth({ useHash: true }), { provide: JWT_STORAGE_SERVICE, useClass: StorageService }]
providers: [
provideCoreAuth({ useHash: true }),
{ provide: JWT_STORAGE_SERVICE, useClass: StorageService },
provideHttpClient(),
provideHttpClientTesting()
]
});
userAccessService = TestBed.inject(UserAccessService);
jwtHelperService = TestBed.inject(JwtHelperService);
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { JwtHelperService } from './jwt-helper.service';
import { ApplicationAccessModel } from '../models/application-access.model';
import { AppConfigService } from '../../app-config/app-config.service';
@@ -24,11 +24,12 @@ import { AppConfigService } from '../../app-config/app-config.service';
providedIn: 'root'
})
export class UserAccessService {
private readonly jwtHelperService = inject(JwtHelperService);
private readonly appConfigService = inject(AppConfigService);
private globalAccess: string[];
private applicationAccess: ApplicationAccessModel[];
constructor(private jwtHelperService: JwtHelperService, private appConfigService: AppConfigService) {}
fetchUserAccess() {
if (this.hasRolesInRealmAccess()) {
this.fetchAccessFromRealmAccess();
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, effect, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Component, effect, Input, OnInit, ViewChild, ViewEncapsulation, inject } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import {
DatetimeAdapter,
@@ -69,6 +69,11 @@ import { IconModule } from '../../../icon/icon.module';
host: { class: 'adf-card-view-dateitem' }
})
export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemModel> implements OnInit {
private readonly dateAdapter = inject<DateAdapter<Date>>(DateAdapter);
private readonly userPreferencesService = inject(UserPreferencesService);
private readonly clipboardService = inject(ClipboardService);
private readonly translateService = inject(TranslationService);
@Input()
displayEmpty = true;
@@ -82,12 +87,7 @@ export class CardViewDateItemComponent extends BaseCardView<CardViewDateItemMode
cardViewDateTimeControl: FormControl<Date> = new FormControl<Date>(null);
constructor(
private dateAdapter: DateAdapter<Date>,
private userPreferencesService: UserPreferencesService,
private clipboardService: ClipboardService,
private translateService: TranslationService
) {
constructor() {
super();
// Use effect to react to locale signal changes (must be in injection context)
effect(() => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, Input, OnChanges, SimpleChange, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';
import { Component, Input, OnChanges, SimpleChange, SimpleChanges, ViewChild, ViewContainerRef, inject } from '@angular/core';
import { CardViewItem } from '../../interfaces/card-view-item.interface';
import { CardItemTypeService } from '../../services/card-item-types.service';
import { DEFAULT_SEPARATOR } from '../card-view-textitem/card-view-textitem.component';
@@ -25,6 +25,8 @@ import { DEFAULT_SEPARATOR } from '../card-view-textitem/card-view-textitem.comp
template: '<ng-template #content />'
})
export class CardViewItemDispatcherComponent implements OnChanges {
private readonly cardItemTypeService = inject(CardItemTypeService);
@Input()
property: CardViewItem;
@@ -58,7 +60,7 @@ export class CardViewItemDispatcherComponent implements OnChanges {
@ViewChild('content', { read: ViewContainerRef, static: true })
content!: ViewContainerRef;
constructor(private cardItemTypeService: CardItemTypeService) {
constructor() {
const dynamicLifeCycleMethods = [
'ngOnInit',
'ngDoCheck',
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, DestroyRef, ElementRef, EventEmitter, Inject, inject, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { Component, DestroyRef, ElementRef, EventEmitter, inject, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { MatSelect } from '@angular/material/select';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -35,6 +35,8 @@ import { IconModule } from '../../../../icon/icon.module';
encapsulation: ViewEncapsulation.None
})
export class SelectFilterInputComponent implements OnInit {
private readonly matSelect = inject<MatSelect>(MatSelect);
@ViewChild('selectFilterInput', { read: ElementRef, static: false }) selectFilterInput: ElementRef;
@Output() change = new EventEmitter<string>();
@@ -43,8 +45,6 @@ export class SelectFilterInputComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef);
constructor(@Inject(MatSelect) private matSelect: MatSelect) {}
onModelChange(value: string) {
this.change.next(value);
}
@@ -61,6 +61,10 @@ const templateTypes = {
host: { class: 'adf-card-view-textitem' }
})
export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemModel> implements OnChanges {
private readonly clipboardService = inject(ClipboardService);
private readonly translateService = inject(TranslationService);
private readonly cd = inject(ChangeDetectorRef);
@Input()
displayEmpty = true;
@@ -80,14 +84,6 @@ export class CardViewTextItemComponent extends BaseCardView<CardViewTextItemMode
private readonly destroyRef = inject(DestroyRef);
constructor(
private clipboardService: ClipboardService,
private translateService: TranslationService,
private cd: ChangeDetectorRef
) {
super();
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.property?.firstChange) {
this.textInput.valueChanges
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Directive, EventEmitter, forwardRef, Input, Output } from '@angular/core';
import { Directive, EventEmitter, forwardRef, Input, Output, inject } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors } from '@angular/forms';
import { CardViewBaseItemModel } from '../models/card-view-baseitem.model';
import { TranslateService } from '@ngx-translate/core';
@@ -31,14 +31,14 @@ import { TranslateService } from '@ngx-translate/core';
]
})
export class CardViewPropertyValidatorDirective {
private readonly translateService = inject(TranslateService);
@Input()
property: CardViewBaseItemModel;
@Output()
validated = new EventEmitter<string[]>();
constructor(private readonly translateService: TranslateService) {}
validate(control: AbstractControl): ValidationErrors | null {
const errors: ValidationErrors | null = this.property.isValid(control.value)
? null
@@ -19,7 +19,7 @@ import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
import { CardViewDateItemProperties } from '../interfaces/card-view.interfaces';
import { LocalizedDatePipe } from '../../pipes/localized-date.pipe';
import { DatePipe } from '@angular/common';
import { DateFnsUtils } from '../../common/utils/date-fns-utils';
type DateItemType = Date | Date[] | null;
@@ -29,8 +29,6 @@ export class CardViewDateItemModel extends CardViewBaseItemModel<DateItemType> i
format: string;
locale: string;
localizedDatePipe: LocalizedDatePipe;
constructor(cardViewDateItemProperties: CardViewDateItemProperties) {
super(cardViewDateItemProperties);
@@ -56,8 +54,10 @@ export class CardViewDateItemModel extends CardViewBaseItemModel<DateItemType> i
}
transformDate(value: Date | string | number): string {
this.localizedDatePipe = new LocalizedDatePipe();
return this.localizedDatePipe.transform(value, this.format, this.locale);
const actualFormat = this.format || 'mediumDate';
const actualLocale = this.locale || 'en-US';
const datePipe = new DatePipe(actualLocale);
return datePipe.transform(value, actualFormat);
}
private prepareDate(date: Date): Date {
@@ -25,7 +25,10 @@ export interface LengthValidatorParams {
export class CardViewItemLengthValidator implements CardViewItemValidator {
message = 'CORE.CARDVIEW.VALIDATORS.LENGTH_VALIDATION_ERROR';
constructor(private minLength: number, private maxLength: number) {}
constructor(
private readonly minLength: number,
private readonly maxLength: number
) {}
isValid(value: string | string[]): boolean {
if (Array.isArray(value)) {
@@ -26,7 +26,11 @@ export interface MatchValidatorParams {
export class CardViewItemMatchValidator implements CardViewItemValidator {
message = 'CORE.CARDVIEW.VALIDATORS.MATCH_VALIDATION_ERROR';
constructor(private expression: string, private flags?: string, private requiresMatch?: boolean) {}
constructor(
private readonly expression: string,
private readonly flags?: string,
private readonly requiresMatch?: boolean
) {}
isValid(value: string | string[]): boolean {
const regex = new RegExp(this.expression, this?.flags);
@@ -25,9 +25,12 @@ export interface MinMaxValidatorParams {
export class CardViewItemMinMaxValidator implements CardViewItemValidator {
message = 'CORE.CARDVIEW.VALIDATORS.MINMAX_VALIDATION_ERROR';
private intValidator: CardViewItemIntValidator;
private readonly intValidator: CardViewItemIntValidator;
constructor(private minValue: number, private maxValue: number) {
constructor(
private readonly minValue: number,
private readonly maxValue: number
) {
this.intValidator = new CardViewItemIntValidator();
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Directive, Input, HostListener, ViewContainerRef, Self, Optional } from '@angular/core';
import { Directive, Input, HostListener, ViewContainerRef, inject } from '@angular/core';
import { ClipboardService } from './clipboard.service';
import { TranslateService } from '@ngx-translate/core';
import { MatTooltip } from '@angular/material/tooltip';
@@ -27,6 +27,11 @@ import { MatTooltip } from '@angular/material/tooltip';
hostDirectives: [MatTooltip]
})
export class ClipboardDirective {
private readonly clipboardService = inject(ClipboardService);
viewContainerRef = inject(ViewContainerRef);
private readonly matTooltip = inject(MatTooltip, { self: true });
private readonly translate = inject(TranslateService, { optional: true });
/** Translation key or message for the tooltip. */
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('adf-clipboard')
@@ -40,13 +45,6 @@ export class ClipboardDirective {
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('clipboard-notification') message: string;
constructor(
private readonly clipboardService: ClipboardService,
public viewContainerRef: ViewContainerRef,
@Self() private readonly matTooltip: MatTooltip,
@Optional() private readonly translate: TranslateService
) {}
@HostListener('mouseenter')
showTooltip() {
const messageKey = this.placeholder || 'CLIPBOARD.CLICK_TO_COPY';
@@ -15,13 +15,14 @@
* limitations under the License.
*/
import { Injectable, Inject } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { NotificationService } from '../notifications/services/notification.service';
@Injectable({ providedIn: 'root' })
export class ClipboardService {
constructor(@Inject(DOCUMENT) private document: any, private notificationService: NotificationService) {}
private readonly document = inject(DOCUMENT);
private readonly notificationService = inject(NotificationService);
/**
* Checks if the target element can have its text copied.
@@ -41,7 +41,7 @@ export class CommentListComponent {
@Output()
clickRow = new EventEmitter<CommentModel>();
private commentsService = inject<CommentsService>(ADF_COMMENTS_SERVICE);
private readonly commentsService = inject<CommentsService>(ADF_COMMENTS_SERVICE);
selectComment(comment: CommentModel): void {
this.clickRow.emit(comment);
@@ -16,17 +16,7 @@
*/
import { CommentModel } from '../models/comment.model';
import {
Component, ElementRef,
EventEmitter,
inject,
Input,
OnChanges,
Output,
SimpleChanges,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { Component, ElementRef, EventEmitter, inject, Input, OnChanges, Output, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { ADF_COMMENTS_SERVICE } from './interfaces/comments.token';
import { CommentsService } from './interfaces/comments-service.interface';
import { CommonModule } from '@angular/common';
@@ -75,7 +65,7 @@ export class CommentsComponent implements OnChanges {
comments: CommentModel[] = [];
beingAdded: boolean = false;
private commentsService = inject<CommentsService>(ADF_COMMENTS_SERVICE);
private readonly commentsService = inject<CommentsService>(ADF_COMMENTS_SERVICE);
private readonly _commentControl = new FormControl('', [this.validateEmptyComment]);
@@ -18,7 +18,7 @@
/* eslint-disable no-console */
import { HttpClientModule } from '@angular/common/http';
import { Component } from '@angular/core';
import { Component, inject as inject_1 } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
import { AppConfigService } from '../../app-config/app-config.service';
import { LogService } from './log.service';
@@ -28,7 +28,7 @@ import { LogService } from './log.service';
providers: [LogService]
})
class ProvidesLogComponent {
constructor(public logService: LogService) {}
logService = inject_1(LogService);
error() {
this.logService.error('Test message');
@@ -17,18 +17,17 @@
/* eslint-disable no-console */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { logLevels, LogLevelsEnum } from '../models/log-levels.model';
import { Subject } from 'rxjs';
/**
* @deprecated This service is deprecated and will be removed in future versions.
*/
@Injectable({
providedIn: 'root'
})
export class LogService {
private readonly appConfig = inject(AppConfigService);
get currentLogLevel(): number {
const configLevel: string = this.appConfig.get<string>(AppConfigValues.LOG_LEVEL);
@@ -41,7 +40,7 @@ export class LogService {
onMessage: Subject<any>;
constructor(private appConfig: AppConfigService) {
constructor() {
this.onMessage = new Subject();
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { AppConfigService } from '../../app-config/app-config.service';
import { TranslationService } from '../../translation/translation.service';
@@ -24,10 +24,16 @@ import { TranslationService } from '../../translation/translation.service';
providedIn: 'root'
})
export class PageTitleService {
private readonly titleService = inject(Title);
private readonly appConfig = inject(AppConfigService);
private readonly translationService = inject(TranslationService);
private originalTitle: string = '';
private translatedTitle: string = '';
constructor(private titleService: Title, private appConfig: AppConfigService, private translationService: TranslationService) {
constructor() {
const translationService = this.translationService;
translationService.translate.onLangChange.subscribe(() => this.onLanguageChanged());
translationService.translate.onTranslationChange.subscribe(() => this.onLanguageChanged());
}
@@ -16,7 +16,7 @@
*/
/* spellchecker: disable */
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
@@ -161,7 +161,10 @@ export class ThumbnailService {
'multipart/related': './assets/images/ft_ic_website.svg'
};
constructor(matIconRegistry: MatIconRegistry, sanitizer: DomSanitizer) {
constructor() {
const matIconRegistry = inject(MatIconRegistry);
const sanitizer = inject(DomSanitizer);
Object.keys(this.mimeTypeIcons).forEach((key) => {
const url = sanitizer.bypassSecurityTrustResourceUrl(this.mimeTypeIcons[key]);
@@ -15,14 +15,14 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Injectable({
providedIn: 'root'
})
export class UrlService {
constructor(private sanitizer: DomSanitizer) {}
private readonly sanitizer = inject(DomSanitizer);
/**
* Creates a trusted object URL from the Blob.
@@ -40,9 +40,13 @@ export type UserPreferenceValues = (typeof UserPreferenceValues)[keyof typeof Us
providedIn: 'root'
})
export class UserPreferencesService {
private document = inject(DOCUMENT);
private rendererFactory = inject(RendererFactory2);
private directionality = inject(Directionality);
translate = inject(TranslateService);
private readonly appConfig = inject(AppConfigService);
private readonly storage = inject(StorageService);
private readonly document = inject(DOCUMENT);
private readonly rendererFactory = inject(RendererFactory2);
private readonly directionality = inject(Directionality);
defaults = {
paginationSize: 25,
@@ -52,7 +56,7 @@ export class UserPreferencesService {
};
private userPreferenceStatus: any = { ...this.defaults };
private onChangeSubject: BehaviorSubject<any>;
private readonly onChangeSubject: BehaviorSubject<any>;
onChange: Observable<any>;
/**
@@ -107,11 +111,7 @@ export class UserPreferencesService {
*/
readonly supportedPageSizesSignal: Signal<number[]>;
constructor(
public translate: TranslateService,
private appConfig: AppConfigService,
private storage: StorageService
) {
constructor() {
this.onChangeSubject = new BehaviorSubject(this.userPreferenceStatus);
this.onChange = this.onChangeSubject.asObservable();
@@ -17,7 +17,7 @@
import { DateFnsAdapter } from '@angular/material-date-fns-adapter';
import { DateFnsUtils } from './date-fns-utils';
import { effect, Inject, Injectable, Optional } from '@angular/core';
import { effect, Injectable, inject } from '@angular/core';
import { MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatDateFormats } from '@angular/material/core';
import { UserPreferencesService } from '../services/user-preferences.service';
import { isValid, Locale, parse } from 'date-fns';
@@ -68,6 +68,8 @@ export const ADF_DATE_FORMATS: MatDateFormats = {
@Injectable({ providedIn: 'root' })
export class AdfDateFnsAdapter extends DateFnsAdapter {
private readonly formats = inject<MatDateFormats>(MAT_DATE_FORMATS, { optional: true });
private _displayFormat?: string = null;
get displayFormat(): string | null {
@@ -78,11 +80,10 @@ export class AdfDateFnsAdapter extends DateFnsAdapter {
this._displayFormat = value ? DateFnsUtils.convertMomentToDateFnsFormat(value) : null;
}
constructor(
@Optional() @Inject(MAT_DATE_LOCALE) matDateLocale: Locale,
@Optional() @Inject(MAT_DATE_FORMATS) private formats: MatDateFormats,
preferences: UserPreferencesService
) {
constructor() {
const matDateLocale = inject<Locale>(MAT_DATE_LOCALE, { optional: true });
const preferences = inject(UserPreferencesService);
// Ensure we have a valid locale for the base class
// If matDateLocale is not provided, use enUS as default
super(matDateLocale || enUS);
@@ -89,7 +89,7 @@ export class DateFnsUtils {
return dateFnsLocale;
}
private static momentToDateFnsMap = {
private static readonly momentToDateFnsMap = {
D: 'd',
Y: 'y',
AZ: 'aa',
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Inject, Injectable, Optional } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { DateFnsUtils } from './date-fns-utils';
import { DatetimeAdapter, MAT_DATETIME_FORMATS, MatDatetimeFormats } from '@mat-datetimepicker/core';
import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core';
@@ -60,6 +60,8 @@ function range<T>(length: number, valueFunction: (index: number) => T): T[] {
@Injectable({ providedIn: 'root' })
export class AdfDateTimeFnsAdapter extends DatetimeAdapter<Date> {
private readonly formats = inject<MatDatetimeFormats>(MAT_DATETIME_FORMATS, { optional: true });
private _displayFormat?: string = null;
get displayFormat(): string | null {
@@ -70,11 +72,10 @@ export class AdfDateTimeFnsAdapter extends DatetimeAdapter<Date> {
this._displayFormat = value ? DateFnsUtils.convertMomentToDateFnsFormat(value) : null;
}
constructor(
@Optional() @Inject(MAT_DATE_LOCALE) matDateLocale: Locale,
@Optional() @Inject(MAT_DATETIME_FORMATS) private formats: MatDatetimeFormats,
dateAdapter: DateAdapter<Date, Locale>
) {
constructor() {
const matDateLocale = inject<Locale>(MAT_DATE_LOCALE, { optional: true });
const dateAdapter = inject<DateAdapter<Date, Locale>>(DateAdapter);
super(dateAdapter);
this.setLocale(matDateLocale);
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { effect, Injectable } from '@angular/core';
import { effect, Injectable, inject } from '@angular/core';
import { DateAdapter } from '@angular/material/core';
import { UserPreferencesService } from '../services/user-preferences.service';
@@ -34,7 +34,9 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
overrideDisplayFormat: string;
constructor(preferences: UserPreferencesService) {
constructor() {
const preferences = inject(UserPreferencesService);
super();
// Use effect to reactively update locale when signal changes
@@ -21,7 +21,7 @@ import { MatMenuItem, MatMenuModule } from '@angular/material/menu';
import { ContextMenuOverlayRef } from './context-menu-overlay';
import { contextMenuAnimation } from './animations';
import { CONTEXT_MENU_DATA } from './context-menu.tokens';
import { AfterViewInit, Component, HostListener, Inject, Optional, QueryList, ViewChildren, ViewEncapsulation } from '@angular/core';
import { AfterViewInit, Component, HostListener, QueryList, ViewChildren, ViewEncapsulation, inject } from '@angular/core';
import { NgForOf, NgIf } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
@@ -41,6 +41,9 @@ import { ContextMenuItem } from './interfaces';
animations: [trigger('panelAnimation', contextMenuAnimation)]
})
export class ContextMenuListComponent implements AfterViewInit {
private readonly contextMenuOverlayRef = inject<ContextMenuOverlayRef>(ContextMenuOverlayRef);
private readonly data = inject(CONTEXT_MENU_DATA, { optional: true });
private keyManager: FocusKeyManager<MatMenuItem>;
@ViewChildren(MatMenuItem) items: QueryList<MatMenuItem>;
links: ContextMenuItem[];
@@ -62,10 +65,7 @@ export class ContextMenuListComponent implements AfterViewInit {
}
}
constructor(
@Inject(ContextMenuOverlayRef) private contextMenuOverlayRef: ContextMenuOverlayRef,
@Optional() @Inject(CONTEXT_MENU_DATA) private data: ContextMenuItem[]
) {
constructor() {
this.links = this.data;
}
@@ -17,7 +17,7 @@
import { Overlay } from '@angular/cdk/overlay';
import { ContextMenuOverlayService } from './context-menu-overlay.service';
import { Injector } from '@angular/core';
import { Injector, runInInjectionContext } from '@angular/core';
import { TestBed } from '@angular/core/testing';
describe('ContextMenuOverlayService', () => {
@@ -43,7 +43,15 @@ describe('ContextMenuOverlayService', () => {
describe('Overlay', () => {
beforeEach(() => {
contextMenuOverlayService = new ContextMenuOverlayService(injector, overlay);
const testInjector = Injector.create({
providers: [
{ provide: Injector, useValue: injector },
{ provide: Overlay, useValue: overlay }
],
parent: TestBed.inject(Injector)
});
contextMenuOverlayService = runInInjectionContext(testInjector, () => new ContextMenuOverlayService());
});
it('should create a custom overlay', () => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable, Injector, ElementRef, ComponentRef } from '@angular/core';
import { Injectable, Injector, ElementRef, ComponentRef, inject } from '@angular/core';
import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { ContextMenuOverlayRef } from './context-menu-overlay';
@@ -33,10 +33,8 @@ const DEFAULT_CONFIG: ContextMenuOverlayConfig = {
providedIn: 'root'
})
export class ContextMenuOverlayService {
constructor(
private injector: Injector,
private overlay: Overlay
) {}
private readonly injector = inject(Injector);
private readonly overlay = inject(Overlay);
open(config: ContextMenuOverlayConfig): ContextMenuOverlayRef {
const overlayConfig = { ...DEFAULT_CONFIG, ...config };
@@ -18,7 +18,7 @@
import { OverlayRef } from '@angular/cdk/overlay';
export class ContextMenuOverlayRef {
constructor(private overlayRef: OverlayRef) {}
constructor(private readonly overlayRef: OverlayRef) {}
close(): void {
this.overlayRef.dispose();
@@ -17,13 +17,15 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { Directive, HostListener, Input } from '@angular/core';
import { Directive, HostListener, Input, inject } from '@angular/core';
import { ContextMenuOverlayService } from './context-menu-overlay.service';
@Directive({
selector: '[adf-context-menu]'
})
export class ContextMenuDirective {
private readonly contextMenuService = inject(ContextMenuOverlayService);
/** Items for the menu. */
@Input('adf-context-menu')
links: any[] | (() => any[]);
@@ -32,8 +34,6 @@ export class ContextMenuDirective {
@Input('adf-context-menu-enabled')
enabled: boolean = false;
constructor(private contextMenuService: ContextMenuOverlayService) {}
@HostListener('contextmenu', ['$event'])
onShowContextMenu(event?: MouseEvent) {
if (this.enabled) {
@@ -23,7 +23,7 @@ import { TranslationService } from '../../../translation';
name: 'columnsSearchFilter'
})
export class ColumnsSearchFilterPipe implements PipeTransform {
private translationService = inject(TranslationService);
private readonly translationService = inject(TranslationService);
transform(columns: DataColumn[], searchByName: string): DataColumn[] {
const result = [];
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, Output, ViewEncapsulation } from '@angular/core';
import { Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, Output, ViewEncapsulation, inject } from '@angular/core';
import { FocusableOption } from '@angular/cdk/a11y';
import { DataRow } from '../../data/data-row.model';
@@ -29,6 +29,8 @@ import { DataRow } from '../../data/data-row.model';
}
})
export class DataTableRowComponent implements FocusableOption {
private readonly element = inject(ElementRef);
@Input() row: DataRow;
@Input() disabled = true;
@@ -74,8 +76,6 @@ export class DataTableRowComponent implements FocusableOption {
}
}
constructor(private element: ElementRef) {}
focus() {
this.element.nativeElement.focus();
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, DebugElement, NO_ERRORS_SCHEMA, QueryList, SimpleChange, TemplateRef, ViewChild } from '@angular/core';
import { Component, DebugElement, QueryList, SimpleChange, TemplateRef, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { DataColumn } from '../../data/data-column.model';
@@ -1631,8 +1631,7 @@ describe('Accessibility', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CustomColumnTemplateComponent],
providers: [{ provide: ConfigurableFocusTrapFactory, useValue: focusTrapFactory }],
schemas: [NO_ERRORS_SCHEMA]
providers: [{ provide: ConfigurableFocusTrapFactory, useValue: focusTrapFactory }]
});
columnCustomTemplate = TestBed.createComponent(CustomColumnTemplateComponent).componentInstance.templateRef;
fixture = TestBed.createComponent(DataTableComponent);
@@ -2020,8 +2019,7 @@ describe('Drag&Drop column header', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CustomColumnTemplateComponent],
schemas: [NO_ERRORS_SCHEMA]
imports: [CustomColumnTemplateComponent]
});
fixture = TestBed.createComponent(DataTableComponent);
testingUtils = new UnitTestingUtils(fixture.debugElement);
@@ -2114,8 +2112,7 @@ describe('Show/hide columns', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CustomColumnTemplateComponent],
schemas: [NO_ERRORS_SCHEMA]
imports: [CustomColumnTemplateComponent]
});
fixture = TestBed.createComponent(DataTableComponent);
dataTable = fixture.componentInstance;
@@ -2222,8 +2219,7 @@ describe('Column Resizing', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CustomColumnTemplateComponent],
schemas: [NO_ERRORS_SCHEMA]
imports: [CustomColumnTemplateComponent]
});
fixture = TestBed.createComponent(DataTableComponent);
dataTable = fixture.componentInstance;
@@ -130,7 +130,12 @@ export type ShowHeaderMode = (typeof ShowHeaderMode)[keyof typeof ShowHeaderMode
host: { class: 'adf-datatable' }
})
export class DataTableComponent implements OnInit, AfterContentInit, OnChanges, DoCheck, OnDestroy, AfterViewInit {
private static MINIMUM_COLUMN_SIZE = 100;
private readonly elementRef = inject(ElementRef);
private readonly matIconRegistry = inject(MatIconRegistry);
private readonly sanitizer = inject(DomSanitizer);
private readonly focusTrapFactory = inject(ConfigurableFocusTrapFactory);
private static readonly MINIMUM_COLUMN_SIZE = 100;
@ViewChildren(DataTableRowComponent)
rowsList: QueryList<DataTableRowComponent>;
@@ -333,9 +338,9 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
private keyManager: FocusKeyManager<DataTableRowComponent>;
private clickObserver: Observer<DataRowEvent>;
private click$: Observable<DataRowEvent>;
private readonly click$: Observable<DataRowEvent>;
private differ: any;
private readonly differ: any;
private rowMenuCache: any = {};
private singleClickStreamSub: Subscription;
@@ -376,13 +381,9 @@ export class DataTableComponent implements OnInit, AfterContentInit, OnChanges,
}
}
constructor(
private readonly elementRef: ElementRef,
differs: IterableDiffers,
private readonly matIconRegistry: MatIconRegistry,
private readonly sanitizer: DomSanitizer,
private readonly focusTrapFactory: ConfigurableFocusTrapFactory
) {
constructor() {
const differs = inject(IterableDiffers);
if (differs) {
this.differ = differs.find([]).create(null);
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { ChangeDetectionStrategy, Component, ViewEncapsulation, Input, computed } from '@angular/core';
import { ChangeDetectionStrategy, Component, ViewEncapsulation, Input, computed, inject } from '@angular/core';
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { EditJsonDialogComponent, EditJsonDialogSettings } from '../../../dialogs/edit-json/edit-json.dialog';
@@ -36,6 +36,8 @@ import { toSignal } from '@angular/core/rxjs-interop';
host: { class: 'adf-datatable-content-cell' }
})
export class JsonCellComponent extends DataTableCellComponent {
private readonly dialog = inject(MatDialog);
/** Editable JSON. */
@Input()
editable: boolean = false;
@@ -47,10 +49,6 @@ export class JsonCellComponent extends DataTableCellComponent {
return !!value || this.editable;
});
constructor(private dialog: MatDialog) {
super();
}
view() {
const rawValue = this.data.getValue(this.row, this.column, this.resolverFn);
const value = typeof rawValue === 'object' ? JSON.stringify(rawValue || {}, null, 2) : String(rawValue ?? '');
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */
import { AfterContentInit, Component, ContentChild, TemplateRef } from '@angular/core';
import { AfterContentInit, Component, ContentChild, TemplateRef, inject } from '@angular/core';
import { DataColumnComponent } from './data-column.component';
@Component({
@@ -25,11 +25,11 @@ import { DataColumnComponent } from './data-column.component';
template: ''
})
export class DateColumnHeaderComponent implements AfterContentInit {
private readonly columnComponent = inject(DataColumnComponent);
@ContentChild(TemplateRef)
public header: TemplateRef<any>;
constructor(private columnComponent: DataColumnComponent) {}
ngAfterContentInit() {
if (this.columnComponent) {
this.columnComponent.header = this.header;
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { ContentChild, Input, Directive } from '@angular/core';
import { ContentChild, Input, Directive, inject } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { AppConfigService } from '../../app-config/app-config.service';
import { DataColumnListComponent } from '../data-column/data-column-list.component';
@@ -45,11 +45,15 @@ export abstract class DataTableSchema<T = unknown> {
protected columnsSchemaSubject$ = new BehaviorSubject<boolean>(false);
isColumnSchemaCreated$ = this.columnsSchemaSubject$.asObservable();
constructor(
private appConfigService: AppConfigService,
protected presetKey: string,
protected presetsModel: any
) {}
protected presetKey: string;
protected presetsModel: any;
protected readonly appConfigService = inject(AppConfigService);
constructor(presetKey: string, presetsModel: any) {
this.presetKey = presetKey;
this.presetsModel = presetsModel;
}
public createDatatableSchema(): void {
this.loadLayoutPresets();
@@ -20,7 +20,11 @@ import { DataRow } from './data-row.model';
// Simple implementation of the DataRow interface.
export class ObjectDataRow implements DataRow {
constructor(private obj: any, public isSelected: boolean = false, public isSelectable: boolean = true) {
constructor(
private readonly obj: any,
public isSelected: boolean = false,
public isSelectable: boolean = true
) {
if (!obj) {
throw new Error('Object source not found');
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Directive, Input, ElementRef, NgZone, OnInit, OnDestroy } from '@angular/core';
import { Directive, Input, ElementRef, NgZone, OnInit, OnDestroy, inject } from '@angular/core';
import { DataRow } from '../data/data-row.model';
import { DataColumn } from '../data/data-column.model';
@@ -23,7 +23,9 @@ import { DataColumn } from '../data/data-column.model';
selector: '[adf-drop-zone]'
})
export class DropZoneDirective implements OnInit, OnDestroy {
private element: HTMLElement;
private readonly ngZone = inject(NgZone);
private readonly element: HTMLElement;
@Input()
dropTarget: 'header' | 'cell' = 'cell';
@@ -34,7 +36,9 @@ export class DropZoneDirective implements OnInit, OnDestroy {
@Input()
dropColumn: DataColumn;
constructor(elementRef: ElementRef, private ngZone: NgZone) {
constructor() {
const elementRef = inject(ElementRef);
this.element = elementRef.nativeElement;
}
@@ -18,6 +18,7 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { HeaderFilterTemplateDirective } from './header-filter-template.directive';
import { Injector, runInInjectionContext } from '@angular/core';
describe('HeaderFilterTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;
@@ -30,7 +31,13 @@ describe('HeaderFilterTemplateDirective', () => {
});
fixture = TestBed.createComponent(DataTableComponent);
dataTable = fixture.componentInstance;
directive = new HeaderFilterTemplateDirective(dataTable);
const injector = Injector.create({
providers: [{ provide: DataTableComponent, useValue: dataTable }],
parent: TestBed.inject(Injector)
});
directive = runInInjectionContext(injector, () => new HeaderFilterTemplateDirective());
});
afterEach(() => {
@@ -15,18 +15,18 @@
* limitations under the License.
*/
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { AfterContentInit, ContentChild, Directive, TemplateRef, inject } from '@angular/core';
import { DataTableComponent } from '../components/datatable/datatable.component';
@Directive({
selector: 'adf-header-filter-template'
})
export class HeaderFilterTemplateDirective implements AfterContentInit {
private readonly dataTable = inject(DataTableComponent, { optional: true });
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {
this.dataTable.headerFilterTemplate = this.template;
@@ -18,6 +18,7 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { LoadingContentTemplateDirective } from './loading-template.directive';
import { Injector, runInInjectionContext } from '@angular/core';
describe('LoadingContentTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;
@@ -30,7 +31,13 @@ describe('LoadingContentTemplateDirective', () => {
});
fixture = TestBed.createComponent(DataTableComponent);
dataTable = fixture.componentInstance;
directive = new LoadingContentTemplateDirective(dataTable);
const injector = Injector.create({
providers: [{ provide: DataTableComponent, useValue: dataTable }],
parent: TestBed.inject(Injector)
});
directive = runInInjectionContext(injector, () => new LoadingContentTemplateDirective());
});
afterEach(() => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { AfterContentInit, ContentChild, Directive, TemplateRef, inject } from '@angular/core';
import { DataTableComponent } from '../components/datatable/datatable.component';
/**
@@ -25,11 +25,11 @@ import { DataTableComponent } from '../components/datatable/datatable.component'
selector: 'adf-loading-content-template, loading-content-template'
})
export class LoadingContentTemplateDirective implements AfterContentInit {
private readonly dataTable = inject(DataTableComponent);
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {
this.dataTable.loadingTemplate = this.template;
@@ -18,9 +18,9 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { MainMenuDataTableTemplateDirective } from './main-data-table-action-template.directive';
import { Injector, runInInjectionContext } from '@angular/core';
describe('MainMenuDataTableTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;
let dataTable: DataTableComponent;
let directive: MainMenuDataTableTemplateDirective;
@@ -28,7 +28,13 @@ describe('MainMenuDataTableTemplateDirective', () => {
beforeEach(() => {
fixture = TestBed.createComponent(DataTableComponent);
dataTable = fixture.componentInstance;
directive = new MainMenuDataTableTemplateDirective(dataTable);
const injector = Injector.create({
providers: [{ provide: DataTableComponent, useValue: dataTable }],
parent: TestBed.inject(Injector)
});
directive = runInInjectionContext(injector, () => new MainMenuDataTableTemplateDirective());
});
afterEach(() => {
@@ -15,18 +15,18 @@
* limitations under the License.
*/
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { AfterContentInit, ContentChild, Directive, TemplateRef, inject } from '@angular/core';
import { DataTableComponent } from '../components/datatable/datatable.component';
@Directive({
selector: 'adf-main-menu-datatable-template'
})
export class MainMenuDataTableTemplateDirective implements AfterContentInit {
private readonly dataTable = inject(DataTableComponent);
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {
this.dataTable.mainActionTemplate = this.template;
@@ -18,6 +18,7 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { NoContentTemplateDirective } from './no-content-template.directive';
import { Injector, runInInjectionContext } from '@angular/core';
describe('NoContentTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;
@@ -30,7 +31,13 @@ describe('NoContentTemplateDirective', () => {
});
fixture = TestBed.createComponent(DataTableComponent);
dataTable = fixture.componentInstance;
directive = new NoContentTemplateDirective(dataTable);
const injector = Injector.create({
providers: [{ provide: DataTableComponent, useValue: dataTable }],
parent: TestBed.inject(Injector)
});
directive = runInInjectionContext(injector, () => new NoContentTemplateDirective());
});
afterEach(() => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { AfterContentInit, ContentChild, Directive, TemplateRef, inject } from '@angular/core';
import { DataTableComponent } from '../components/datatable/datatable.component';
/**
@@ -25,11 +25,11 @@ import { DataTableComponent } from '../components/datatable/datatable.component'
selector: 'adf-no-content-template, no-content-template'
})
export class NoContentTemplateDirective implements AfterContentInit {
private readonly dataTable = inject(DataTableComponent);
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {
this.dataTable.noContentTemplate = this.template;
@@ -18,6 +18,7 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DataTableComponent } from '../components/datatable/datatable.component';
import { NoPermissionTemplateDirective } from './no-permission-template.directive';
import { Injector, runInInjectionContext } from '@angular/core';
describe('NoPermissionTemplateDirective', () => {
let fixture: ComponentFixture<DataTableComponent>;
@@ -30,7 +31,13 @@ describe('NoPermissionTemplateDirective', () => {
});
fixture = TestBed.createComponent(DataTableComponent);
dataTable = fixture.componentInstance;
directive = new NoPermissionTemplateDirective(dataTable);
const injector = Injector.create({
providers: [{ provide: DataTableComponent, useValue: dataTable }],
parent: TestBed.inject(Injector)
});
directive = runInInjectionContext(injector, () => new NoPermissionTemplateDirective());
});
afterEach(() => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { AfterContentInit, ContentChild, Directive, TemplateRef, inject } from '@angular/core';
import { DataTableComponent } from '../components/datatable/datatable.component';
/**
@@ -25,11 +25,11 @@ import { DataTableComponent } from '../components/datatable/datatable.component'
selector: 'adf-no-permission-template, no-permission-template'
})
export class NoPermissionTemplateDirective implements AfterContentInit {
private readonly dataTable = inject(DataTableComponent);
@ContentChild(TemplateRef)
template: any;
constructor(private dataTable: DataTableComponent) {}
ngAfterContentInit() {
if (this.dataTable) {
this.dataTable.noPermissionTemplate = this.template;
@@ -67,10 +67,18 @@ describe('ResizableDirective', () => {
const injector = TestBed.inject(Injector);
spyOn(ngZone, 'runOutsideAngular').and.callFake((fn) => fn());
spyOn(ngZone, 'run').and.callFake((fn) => fn());
runInInjectionContext(injector, () => {
directive = new ResizableDirective(renderer, element, ngZone);
const testInjector = Injector.create({
providers: [
{ provide: Renderer2, useValue: renderer },
{ provide: ElementRef, useValue: element },
{ provide: NgZone, useValue: ngZone }
],
parent: injector
});
directive = runInInjectionContext(testInjector, () => new ResizableDirective());
directive.ngOnInit();
});
@@ -26,6 +26,10 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
exportAs: 'adf-resizable'
})
export class ResizableDirective implements OnInit, OnDestroy {
private readonly renderer = inject(Renderer2);
private readonly element = inject<ElementRef<HTMLElement>>(ElementRef);
private readonly zone = inject(NgZone);
/**
* Emitted when the mouse is pressed and a resize event is about to begin.
*/
@@ -71,7 +75,10 @@ export class ResizableDirective implements OnInit, OnDestroy {
private readonly destroyRef = inject(DestroyRef);
constructor(private readonly renderer: Renderer2, private readonly element: ElementRef<HTMLElement>, private readonly zone: NgZone) {
constructor() {
const renderer = this.renderer;
const zone = this.zone;
this.pointerDown = new Observable((observer: Observer<IResizeMouseEvent>) => {
zone.runOutsideAngular(() => {
this.unsubscribeMouseDown = renderer.listen('document', 'mousedown', (event: MouseEvent) => {
@@ -15,7 +15,8 @@
* limitations under the License.
*/
import { ElementRef, NgZone, Renderer2 } from '@angular/core';
import { ElementRef, NgZone, Renderer2, Injector, runInInjectionContext } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ResizeHandleDirective } from './resize-handle.directive';
import { ResizableDirective } from './resizable.directive';
import { Subject } from 'rxjs';
@@ -38,7 +39,16 @@ describe('ResizeHandleDirective', () => {
mousemove: new Subject()
});
directive = new ResizeHandleDirective(renderer, element, ngZone);
const injector = Injector.create({
providers: [
{ provide: Renderer2, useValue: renderer },
{ provide: ElementRef, useValue: element },
{ provide: NgZone, useValue: ngZone }
],
parent: TestBed.inject(Injector)
});
directive = runInInjectionContext(injector, () => new ResizeHandleDirective());
directive.resizableContainer = resizableContainer;
});
@@ -16,12 +16,16 @@
*/
import { ResizableDirective } from './resizable.directive';
import { Directive, ElementRef, HostListener, Input, NgZone, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Directive, ElementRef, HostListener, Input, NgZone, OnDestroy, OnInit, Renderer2, inject } from '@angular/core';
@Directive({
selector: '[adf-resize-handle]'
})
export class ResizeHandleDirective implements OnInit, OnDestroy {
private readonly renderer = inject(Renderer2);
private readonly element = inject(ElementRef);
private readonly zone = inject(NgZone);
/**
* Reference to ResizableDirective
*/
@@ -30,7 +34,6 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {
private unlistenMouseDown?: () => void;
private unlistenMouseMove?: () => void;
private unlistenMouseUp?: () => void;
constructor(private readonly renderer: Renderer2, private readonly element: ElementRef, private readonly zone: NgZone) {}
@HostListener('keydown', ['$event'])
onKeydown(event: KeyboardEvent): void {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, Inject, SecurityContext, ViewEncapsulation } from '@angular/core';
import { Component, SecurityContext, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { DomSanitizer } from '@angular/platform-browser';
import { TranslatePipe } from '@ngx-translate/core';
@@ -41,6 +41,9 @@ export interface ConfirmDialogComponentProps {
imports: [TranslatePipe, MatDialogModule, NgIf, MatButtonModule]
})
export class ConfirmDialogComponent {
private readonly sanitizer = inject(DomSanitizer);
private readonly data = inject<ConfirmDialogComponentProps>(MAT_DIALOG_DATA) ?? {};
title: string;
message: string;
yesLabel: string;
@@ -48,14 +51,13 @@ export class ConfirmDialogComponent {
thirdOptionLabel: string;
htmlContent: string;
constructor(@Inject(MAT_DIALOG_DATA) data: ConfirmDialogComponentProps, private sanitizer: DomSanitizer) {
data = data || {};
this.title = data.title || 'ADF_CONFIRM_DIALOG.TITLE';
this.message = data.message || 'ADF_CONFIRM_DIALOG.MESSAGE';
this.yesLabel = data.yesLabel || 'ADF_CONFIRM_DIALOG.YES_LABEL';
this.thirdOptionLabel = data.thirdOptionLabel;
this.noLabel = data.noLabel || 'ADF_CONFIRM_DIALOG.NO_LABEL';
this.htmlContent = data.htmlContent;
constructor() {
this.title = this.data.title || 'ADF_CONFIRM_DIALOG.TITLE';
this.message = this.data.message || 'ADF_CONFIRM_DIALOG.MESSAGE';
this.yesLabel = this.data.yesLabel || 'ADF_CONFIRM_DIALOG.YES_LABEL';
this.thirdOptionLabel = this.data.thirdOptionLabel;
this.noLabel = this.data.noLabel || 'ADF_CONFIRM_DIALOG.NO_LABEL';
this.htmlContent = this.data.htmlContent;
}
sanitizedHtmlContent(): string {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, Inject, InjectionToken, Injector, ViewEncapsulation } from '@angular/core';
import { Component, InjectionToken, Injector, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { AdditionalDialogActionButton, DialogData } from './dialog-data.interface';
import { BehaviorSubject } from 'rxjs';
@@ -36,6 +36,9 @@ export const DIALOG_COMPONENT_DATA = new InjectionToken<any>('dialog component d
encapsulation: ViewEncapsulation.None
})
export class DialogComponent {
data = inject<DialogData>(MAT_DIALOG_DATA);
dialogRef = inject<MatDialogRef<DialogComponent>>(MatDialogRef);
isConfirmButtonDisabled$ = new BehaviorSubject<boolean>(false);
isCloseButtonHidden: boolean;
isCancelButtonHidden: boolean;
@@ -47,11 +50,9 @@ export class DialogComponent {
dataInjector: Injector;
constructor(
@Inject(MAT_DIALOG_DATA)
public data: DialogData,
public dialogRef: MatDialogRef<DialogComponent>
) {
constructor() {
const data = this.data;
if (data) {
this.isCancelButtonHidden = data.isCancelButtonHidden || false;
this.isCloseButtonHidden = data.isCloseButtonHidden || false;
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, Inject, OnInit, Input, ViewEncapsulation } from '@angular/core';
import { Component, OnInit, Input, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
@@ -36,14 +36,14 @@ export interface EditJsonDialogSettings {
host: { class: 'adf-edit-json-dialog' }
})
export class EditJsonDialogComponent implements OnInit {
private readonly settings = inject<EditJsonDialogSettings>(MAT_DIALOG_DATA);
editable: boolean = false;
title: string = 'JSON';
@Input()
value: string = '';
constructor(@Inject(MAT_DIALOG_DATA) private settings: EditJsonDialogSettings) {}
ngOnInit() {
if (this.settings) {
this.editable = this.settings.editable;
@@ -15,7 +15,7 @@
* 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 } from '@angular/material/dialog';
import { UnsavedChangesDialogData } from './unsaved-changes-dialog.model';
import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
@@ -44,12 +44,10 @@ import { IconModule } from '../../icon/icon.module';
imports: [MatDialogModule, TranslatePipe, MatButtonModule, IconModule, CommonModule, MatCheckboxModule, ReactiveFormsModule]
})
export class UnsavedChangesDialogComponent implements OnInit {
dialogData: UnsavedChangesDialogData;
data = inject<UnsavedChangesDialogData>(MAT_DIALOG_DATA);
private readonly userPreferencesService = inject(UserPreferencesService);
constructor(
@Inject(MAT_DIALOG_DATA) public data: UnsavedChangesDialogData,
private userPreferencesService: UserPreferencesService
) {}
dialogData: UnsavedChangesDialogData;
ngOnInit() {
this.dialogData = {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable, of } from 'rxjs';
import { MatDialog } from '@angular/material/dialog';
@@ -31,11 +31,13 @@ import { AuthenticationService, AuthGuardService } from '../../auth';
providedIn: 'root'
})
export class UnsavedChangesGuard implements CanDeactivate<any> {
private readonly dialog = inject(MatDialog);
private readonly authenticationService = inject(AuthenticationService);
private readonly authGuardBaseService = inject(AuthGuardService);
unsaved = false;
data: UnsavedChangesDialogData;
constructor(private dialog: MatDialog, private authenticationService: AuthenticationService, private authGuardBaseService: AuthGuardService) {}
/**
* Allows to deactivate route when there is no unsaved changes, otherwise displays dialog to confirm discarding changes.
*
@@ -17,13 +17,17 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { Directive, ElementRef, Input, Renderer2, AfterViewChecked } from '@angular/core';
import { Directive, ElementRef, Input, Renderer2, AfterViewChecked, inject } from '@angular/core';
import { HighlightTransformService, HighlightTransformResult } from '../common/services/highlight-transform.service';
@Directive({
selector: '[adf-highlight]'
})
export class HighlightDirective implements AfterViewChecked {
private readonly el = inject(ElementRef);
private readonly renderer = inject(Renderer2);
private readonly highlightTransformService = inject(HighlightTransformService);
/** Class selector for highlightable elements. */
@Input('adf-highlight-selector')
selector: string = '';
@@ -36,8 +40,6 @@ export class HighlightDirective implements AfterViewChecked {
@Input('adf-highlight-class')
classToApply: string = 'adf-highlight';
constructor(private el: ElementRef, private renderer: Renderer2, private highlightTransformService: HighlightTransformService) {}
ngAfterViewChecked() {
this.highlight();
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { AfterViewInit, DestroyRef, Directive, EventEmitter, inject, Inject, Output } from '@angular/core';
import { AfterViewInit, DestroyRef, Directive, EventEmitter, inject, Output } from '@angular/core';
import { MatSelect } from '@angular/material/select';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@@ -25,6 +25,8 @@ const SELECT_ITEM_HEIGHT_EM = 3;
selector: '[adf-infinite-select-scroll]'
})
export class InfiniteSelectScrollDirective implements AfterViewInit {
private readonly matSelect = inject<MatSelect>(MatSelect);
static readonly MAX_ITEMS = 50;
/** Emitted when scroll reaches the last item. */
@@ -33,8 +35,6 @@ export class InfiniteSelectScrollDirective implements AfterViewInit {
private readonly destroyRef = inject(DestroyRef);
private itemHeightToWaitBeforeLoadNext = 0;
constructor(@Inject(MatSelect) private matSelect: MatSelect) {}
ngAfterViewInit() {
this.matSelect.openedChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((opened: boolean) => {
if (opened) {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Input, Directive, ElementRef, OnInit, Renderer2 } from '@angular/core';
import { Input, Directive, ElementRef, OnInit, Renderer2, inject } from '@angular/core';
import { Router } from '@angular/router';
import { AppConfigService } from '../app-config/app-config.service';
import { AuthenticationService } from '../auth/services/authentication.service';
@@ -24,6 +24,12 @@ import { AuthenticationService } from '../auth/services/authentication.service';
selector: '[adf-logout]'
})
export class LogoutDirective implements OnInit {
private readonly elementRef = inject(ElementRef);
private readonly renderer = inject(Renderer2);
private readonly router = inject(Router);
private readonly appConfig = inject(AppConfigService);
private readonly authenticationService = inject(AuthenticationService);
/** URI to redirect to after logging out. */
@Input()
redirectUri: string;
@@ -32,14 +38,6 @@ export class LogoutDirective implements OnInit {
@Input()
enableRedirect: boolean = true;
constructor(
private elementRef: ElementRef,
private renderer: Renderer2,
private router: Router,
private appConfig: AppConfigService,
private authenticationService: AuthenticationService
) {}
ngOnInit() {
if (this.elementRef.nativeElement) {
this.renderer.listen(this.elementRef.nativeElement, 'click', (evt) => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, Input, SecurityContext } from '@angular/core';
import { Component, Input, SecurityContext, inject } from '@angular/core';
import { animate, style, transition, trigger } from '@angular/animations';
import { DomSanitizer } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
@@ -33,13 +33,13 @@ import { CommonModule } from '@angular/common';
]
})
export class TooltipCardComponent {
private readonly sanitizer = inject(DomSanitizer);
@Input() image = '';
@Input() text = '';
@Input() htmlContent = '';
@Input() width = '300';
constructor(private sanitizer: DomSanitizer) {}
sanitizedHtmlContent(): string {
return this.sanitizer.sanitize(SecurityContext.HTML, this.htmlContent);
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { ComponentRef, Directive, ElementRef, HostListener, Input, OnDestroy, OnInit } from '@angular/core';
import { ComponentRef, Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, inject } from '@angular/core';
import { Overlay, OverlayPositionBuilder, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { TooltipCardComponent } from './tooltip-card.component';
@@ -24,6 +24,10 @@ import { TooltipCardComponent } from './tooltip-card.component';
selector: '[adf-tooltip-card]'
})
export class TooltipCardDirective implements OnInit, OnDestroy {
private readonly overlay = inject(Overlay);
private readonly overlayPositionBuilder = inject(OverlayPositionBuilder);
private readonly elementRef = inject(ElementRef);
@Input('adf-tooltip-card') text = '';
@Input() image = '';
@Input() width = '300';
@@ -37,12 +41,6 @@ export class TooltipCardDirective implements OnInit, OnDestroy {
private overlayRef: OverlayRef;
constructor(
private overlay: Overlay,
private overlayPositionBuilder: OverlayPositionBuilder,
private elementRef: ElementRef
) {}
ngOnDestroy(): void {
if (this.overlayRef) {
this.hide();
@@ -15,8 +15,8 @@
* limitations under the License.
*/
import { ElementRef } from '@angular/core';
import { fakeAsync, tick } from '@angular/core/testing';
import { ElementRef, Renderer2, NgZone, Injector, runInInjectionContext } from '@angular/core';
import { fakeAsync, tick, TestBed } from '@angular/core/testing';
import { UploadDirective } from './upload.directive';
describe('UploadDirective', () => {
@@ -26,9 +26,26 @@ describe('UploadDirective', () => {
beforeEach(() => {
nativeElement = {
classList: jasmine.createSpyObj('classList', ['add', 'remove']),
dispatchEvent: () => {}
dispatchEvent: () => {},
parentElement: {
appendChild: jasmine.createSpy('appendChild')
}
};
directive = new UploadDirective(new ElementRef(nativeElement), null, null);
const mockRenderer = jasmine.createSpyObj('Renderer2', ['createElement']);
const mockNgZone = jasmine.createSpyObj('NgZone', ['runOutsideAngular']);
mockNgZone.runOutsideAngular.and.callFake((fn: () => void) => fn());
const injector = Injector.create({
providers: [
{ provide: ElementRef, useValue: new ElementRef(nativeElement) },
{ provide: Renderer2, useValue: mockRenderer },
{ provide: NgZone, useValue: mockNgZone }
],
parent: TestBed.inject(Injector)
});
directive = runInInjectionContext(injector, () => new UploadDirective());
});
it('should be enabled by default', () => {
@@ -17,13 +17,17 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { Directive, ElementRef, HostListener, Input, NgZone, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Directive, ElementRef, HostListener, Input, NgZone, OnDestroy, OnInit, Renderer2, inject } from '@angular/core';
import { FileInfo, FileUtils } from '../common/utils/file-utils';
@Directive({
selector: '[adf-upload]'
})
export class UploadDirective implements OnInit, OnDestroy {
private readonly el = inject(ElementRef);
private readonly renderer = inject(Renderer2);
private readonly ngZone = inject(NgZone);
/** Enables/disables uploading. */
@Input('adf-upload')
enabled: boolean = true;
@@ -53,11 +57,13 @@ export class UploadDirective implements OnInit, OnDestroy {
isDragging: boolean = false;
private cssClassName: string = 'adf-upload__dragging';
private readonly cssClassName: string = 'adf-upload__dragging';
private upload: HTMLInputElement;
private element: HTMLElement;
private readonly element: HTMLElement;
constructor() {
const el = this.el;
constructor(private el: ElementRef, private renderer: Renderer2, private ngZone: NgZone) {
this.element = el.nativeElement;
}
@@ -32,7 +32,8 @@ import {
SimpleChanges,
ViewChild,
ViewChildren,
ViewEncapsulation
ViewEncapsulation,
inject
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatChip, MatChipsModule } from '@angular/material/chips';
@@ -51,6 +52,8 @@ import { IconModule } from '../icon/icon.module';
encapsulation: ViewEncapsulation.None
})
export class DynamicChipListComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy {
private readonly changeDetectorRef = inject(ChangeDetectorRef);
/* eslint no-underscore-dangle: ["error", { "allow": ["_elementRef"] }]*/
/** Provide if you want to use paginated chips. */
@Input()
@@ -103,15 +106,13 @@ export class DynamicChipListComponent implements OnChanges, OnInit, AfterViewIni
private initialLimitChipsDisplayed: boolean;
private viewMoreButtonLeftOffsetBeforeFlexDirection: number;
private requestedDisplayingAllChips = false;
private resizeObserver = new ResizeObserver(() => {
private readonly resizeObserver = new ResizeObserver(() => {
if (this.initialLimitChipsDisplayed && this.chipsToDisplay.length) {
this.calculateChipsToDisplay();
this.changeDetectorRef.detectChanges();
}
});
constructor(private changeDetectorRef: ChangeDetectorRef) {}
ngOnChanges(changes: SimpleChanges): void {
if (changes.pagination) {
this.limitChipsDisplayed = this.pagination?.hasMoreItems;
@@ -16,7 +16,7 @@
*/
import { NgClass, NgForOf, NgIf, NgStyle, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectorRef, Component, Inject, inject, Injector, Input, OnDestroy, OnInit, Optional, ViewEncapsulation } from '@angular/core';
import { ChangeDetectorRef, Component, inject, Injector, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatTabsModule } from '@angular/material/tabs';
@@ -70,10 +70,12 @@ import { IconModule } from '../../icon/icon.module';
encapsulation: ViewEncapsulation.None
})
export class FormRendererComponent<T> implements OnInit, OnDestroy {
private readonly middlewareServices = inject<FormFieldModelRenderMiddleware[]>(FORM_FIELD_MODEL_RENDER_MIDDLEWARE, { optional: true }) ?? [];
public readonly formService = inject(FormService);
private readonly formRulesManager = inject(FormRulesManager<T>);
private readonly dialog = inject(MatDialog);
private cdr = inject(ChangeDetectorRef);
private readonly cdr = inject(ChangeDetectorRef);
@Input({ required: true })
formDefinition: FormModel;
@@ -85,12 +87,6 @@ export class FormRendererComponent<T> implements OnInit, OnDestroy {
fields: FormFieldModel[];
constructor(
@Optional()
@Inject(FORM_FIELD_MODEL_RENDER_MIDDLEWARE)
private middlewareServices?: FormFieldModelRenderMiddleware[]
) {}
ngOnInit(): void {
this.runMiddlewareServices();
if (!this.readOnly) {
@@ -18,7 +18,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { CurrencyPipe, NgIf } from '@angular/common';
import { Component, OnInit, ViewEncapsulation, InjectionToken, Inject, Optional, inject, DestroyRef } from '@angular/core';
import { Component, OnInit, ViewEncapsulation, InjectionToken, inject, DestroyRef } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
@@ -57,6 +57,9 @@ export const ADF_AMOUNT_SETTINGS = new InjectionToken<Observable<AmountWidgetSet
encapsulation: ViewEncapsulation.None
})
export class AmountWidgetComponent extends WidgetComponent implements OnInit {
private readonly currencyPipe = inject(CurrencyPipe);
private readonly translationService = inject(TranslationService);
static DEFAULT_CURRENCY: string = '$';
private showPlaceholder = true;
private readonly destroyRef = inject(DestroyRef);
@@ -85,11 +88,9 @@ export class AmountWidgetComponent extends WidgetComponent implements OnInit {
return this.currencyPipe.transform(this.field.placeholder, this.currency, this.currencyDisplay, this.decimalProperty, this.locale);
}
constructor(
@Optional() @Inject(ADF_AMOUNT_SETTINGS) settings: Observable<AmountWidgetSettings> | AmountWidgetSettings,
private currencyPipe: CurrencyPipe,
private translationService: TranslationService
) {
constructor() {
const settings = inject<Observable<AmountWidgetSettings> | AmountWidgetSettings>(ADF_AMOUNT_SETTINGS, { optional: true });
super();
if (isObservable(settings)) {
settings.pipe(takeUntilDestroyed()).subscribe((data: AmountWidgetSettings) => {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { ChangeDetectorRef, Component, inject, AfterViewInit, DestroyRef, InjectionToken, Optional, Inject } from '@angular/core';
import { ChangeDetectorRef, Component, inject, AfterViewInit, DestroyRef, InjectionToken } from '@angular/core';
import { debounceTime, filter, isObservable, Observable } from 'rxjs';
import { FormRulesEvent } from '../../../events';
import { FormExpressionService } from '../../../services/form-expression.service';
@@ -39,14 +39,18 @@ export abstract class BaseDisplayTextWidgetComponent extends WidgetComponent imp
private enableExpressionEvaluation: boolean = false;
protected originalFieldValue?: string;
constructor(@Optional() @Inject(ADF_DISPLAY_TEXT_SETTINGS) settings: Observable<DisplayTextWidgetSettings> | DisplayTextWidgetSettings) {
private readonly settings = inject<Observable<DisplayTextWidgetSettings> | DisplayTextWidgetSettings>(ADF_DISPLAY_TEXT_SETTINGS, {
optional: true
});
constructor() {
super();
if (isObservable(settings)) {
settings.pipe(takeUntilDestroyed()).subscribe((data: DisplayTextWidgetSettings) => {
if (isObservable(this.settings)) {
this.settings.pipe(takeUntilDestroyed()).subscribe((data: DisplayTextWidgetSettings) => {
this.updateSettingsBasedProperties(data);
});
} else {
this.updateSettingsBasedProperties(settings);
this.updateSettingsBasedProperties(this.settings);
}
}
@@ -27,7 +27,7 @@ export interface FormFieldValidator {
}
export class RequiredFieldValidator implements FormFieldValidator {
private supportedTypes = [
private readonly supportedTypes = [
FormFieldTypes.TEXT,
FormFieldTypes.MULTILINE_TEXT,
FormFieldTypes.NUMBER,
@@ -78,7 +78,7 @@ export class RequiredFieldValidator implements FormFieldValidator {
}
export class NumberFieldValidator implements FormFieldValidator {
private supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.AMOUNT];
private readonly supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.AMOUNT];
static isNumber(value: any): boolean {
return isNumberValue(value);
@@ -109,7 +109,7 @@ export class NumberFieldValidator implements FormFieldValidator {
}
export class MinLengthFieldValidator implements FormFieldValidator {
private supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT];
private readonly supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT];
isSupported(field: FormFieldModel): boolean {
return field && this.supportedTypes.indexOf(field.type) > -1 && field.minLength > 0;
@@ -130,8 +130,8 @@ export class MinLengthFieldValidator implements FormFieldValidator {
export class MaxLengthFieldValidator implements FormFieldValidator {
constructor(
private supportedTypes: FormFieldTypes[] = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT],
private maxLength?: number
private readonly supportedTypes: FormFieldTypes[] = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT],
private readonly maxLength?: number
) {}
isSupported(field: FormFieldModel): boolean {
@@ -159,7 +159,7 @@ export class MaxLengthFieldValidator implements FormFieldValidator {
}
export class MinValueFieldValidator implements FormFieldValidator {
private supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.DECIMAL, FormFieldTypes.AMOUNT];
private readonly supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.DECIMAL, FormFieldTypes.AMOUNT];
isSupported(field: FormFieldModel): boolean {
return field && this.supportedTypes.indexOf(field.type) > -1 && NumberFieldValidator.isNumber(field.minValue);
@@ -183,7 +183,7 @@ export class MinValueFieldValidator implements FormFieldValidator {
}
export class MaxValueFieldValidator implements FormFieldValidator {
private supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.DECIMAL, FormFieldTypes.AMOUNT];
private readonly supportedTypes = [FormFieldTypes.NUMBER, FormFieldTypes.DECIMAL, FormFieldTypes.AMOUNT];
isSupported(field: FormFieldModel): boolean {
return field && this.supportedTypes.indexOf(field.type) > -1 && NumberFieldValidator.isNumber(field.maxValue);
@@ -207,7 +207,7 @@ export class MaxValueFieldValidator implements FormFieldValidator {
}
export class RegExFieldValidator implements FormFieldValidator {
private supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT];
private readonly supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT];
isSupported(field: FormFieldModel): boolean {
return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.regexPattern;
@@ -226,7 +226,7 @@ export class RegExFieldValidator implements FormFieldValidator {
}
export class FixedValueFieldValidator implements FormFieldValidator {
private supportedTypes = [FormFieldTypes.TYPEAHEAD];
private readonly supportedTypes = [FormFieldTypes.TYPEAHEAD];
isSupported(field: FormFieldModel): boolean {
return field && this.supportedTypes.indexOf(field.type) > -1;
@@ -264,7 +264,7 @@ export class FixedValueFieldValidator implements FormFieldValidator {
}
export class DecimalFieldValidator implements FormFieldValidator {
private supportedTypes = [FormFieldTypes.DECIMAL];
private readonly supportedTypes = [FormFieldTypes.DECIMAL];
isSupported(field: FormFieldModel): boolean {
return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.value;
@@ -25,12 +25,16 @@ import { FormOutcomeModel } from './form-outcome.model';
import { FormModel } from './form.model';
import { TabModel } from './tab.model';
import { fakeMetadataForm, mockDisplayExternalPropertyForm, mockFormWithSections, fakeValidatorMock } from '../../mock/form.mock';
import { TestBed } from '@angular/core/testing';
describe('FormModel', () => {
let formService: FormService;
beforeEach(() => {
formService = new FormService();
TestBed.configureTestingModule({
providers: [FormService]
});
formService = TestBed.inject(FormService);
});
it('should store original json', () => {
@@ -41,7 +41,7 @@ import { TranslatePipe } from '@ngx-translate/core';
encapsulation: ViewEncapsulation.None
})
export class JsonWidgetComponent extends WidgetComponent {
private dialog = inject(MatDialog);
private readonly dialog = inject(MatDialog);
view() {
const rawValue = this.field.value;
@@ -49,7 +49,7 @@ import { WidgetComponent } from '../widget.component';
export class NumberWidgetComponent extends WidgetComponent implements OnInit {
displayValue: number;
private decimalNumberPipe = inject(DecimalNumberPipe);
private readonly decimalNumberPipe = inject(DecimalNumberPipe);
ngOnInit() {
if (this.field.readOnly) {
@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector, @typescript-eslint/no-use-before-define, @angular-eslint/no-input-rename */
import { Directive, ElementRef, forwardRef, HostListener, Input, OnChanges, Renderer2, SimpleChanges } from '@angular/core';
import { Directive, ElementRef, forwardRef, HostListener, Input, OnChanges, Renderer2, SimpleChanges, inject } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
@@ -34,13 +34,16 @@ export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class InputMaskDirective implements OnChanges, ControlValueAccessor {
private readonly el = inject(ElementRef);
private readonly render = inject(Renderer2);
/** Object defining mask and "reversed" status. */
@Input('textMask') inputMask: {
mask: string;
isReversed: boolean;
};
private translationMask = {
private readonly translationMask = {
'0': { pattern: /\d/ },
'9': { pattern: /\d/, optional: true },
'#': { pattern: /\d/, recursive: true },
@@ -48,11 +51,9 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
S: { pattern: /[a-zA-Z]/ }
};
private byPassKeys = [9, 16, 17, 18, 36, 37, 38, 39, 40, 91];
private readonly byPassKeys = [9, 16, 17, 18, 36, 37, 38, 39, 40, 91];
private value;
private invalidCharacters = [];
constructor(private el: ElementRef, private render: Renderer2) {}
private readonly invalidCharacters = [];
_onChange = (_: any) => {};

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