AAE-36664 additional linting rules, cleanup (#11084)

This commit is contained in:
Denys Vuika
2025-08-13 08:01:09 -04:00
committed by GitHub
parent e83c8f7fd7
commit b16e326ac3
71 changed files with 235 additions and 2994 deletions
+6
View File
@@ -28,6 +28,11 @@ module.exports = {
'plugin:@angular-eslint/recommended', 'plugin:@angular-eslint/recommended',
'plugin:@angular-eslint/template/process-inline-templates', 'plugin:@angular-eslint/template/process-inline-templates',
'plugin:jsdoc/recommended-typescript-error' 'plugin:jsdoc/recommended-typescript-error'
// Uncomment this once all linting issues are fixed
// Note to developers:
// you can uncomment the full ruleset locally when fixing issues, and then comment
// that will allow splitting the work into smaller chunks
// 'plugin:unicorn/recommended'
], ],
plugins: [ plugins: [
'eslint-plugin-unicorn', 'eslint-plugin-unicorn',
@@ -152,6 +157,7 @@ module.exports = {
'rxjs/no-subject-value': 'error', 'rxjs/no-subject-value': 'error',
'rxjs/no-unsafe-takeuntil': 'error', 'rxjs/no-unsafe-takeuntil': 'error',
'unicorn/filename-case': 'error', 'unicorn/filename-case': 'error',
'unicorn/prefer-optional-catch-binding': 'error',
'@typescript-eslint/no-unused-expressions': [ '@typescript-eslint/no-unused-expressions': [
'error', 'error',
{ {
@@ -20,7 +20,6 @@ import { ContentService } from './content.service';
import { AppConfigService, AuthenticationService, RedirectAuthService, StorageService } from '@alfresco/adf-core'; import { AppConfigService, AuthenticationService, RedirectAuthService, StorageService } from '@alfresco/adf-core';
import { Node, PermissionsInfo } from '@alfresco/js-api'; import { Node, PermissionsInfo } from '@alfresco/js-api';
import { EMPTY, of } from 'rxjs'; import { EMPTY, of } from 'rxjs';
import { HttpClientTestingModule } from '@angular/common/http/testing';
describe('ContentService', () => { describe('ContentService', () => {
let contentService: ContentService; let contentService: ContentService;
@@ -29,7 +28,6 @@ describe('ContentService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ContentService, AuthenticationService, { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } }] providers: [ContentService, AuthenticationService, { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } }]
}); });
authService = TestBed.inject(AuthenticationService); authService = TestBed.inject(AuthenticationService);
@@ -73,7 +73,11 @@ export class RenditionService {
return this._versionsApi; return this._versionsApi;
} }
constructor(private apiService: AlfrescoApiService, private translateService: TranslationService, private viewUtilsService: ViewUtilService) {} constructor(
private readonly apiService: AlfrescoApiService,
private readonly translateService: TranslationService,
private readonly viewUtilsService: ViewUtilService
) {}
getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string { getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string {
return renditionExists && type !== RenditionService.ContentGroup.IMAGE return renditionExists && type !== RenditionService.ContentGroup.IMAGE
@@ -167,7 +171,7 @@ export class RenditionService {
} }
try { try {
return versionId ? await this.waitNodeRendition(nodeId, renditionId, versionId) : await this.waitNodeRendition(nodeId, renditionId); return versionId ? await this.waitNodeRendition(nodeId, renditionId, versionId) : await this.waitNodeRendition(nodeId, renditionId);
} catch (e) { } catch {
return null; return null;
} }
} catch { } catch {
@@ -54,7 +54,7 @@ const customSiteList = {
describe('DropdownSitesComponent', () => { describe('DropdownSitesComponent', () => {
let loader: HarnessLoader; let loader: HarnessLoader;
let component: any; let component: DropdownSitesComponent;
let fixture: ComponentFixture<DropdownSitesComponent>; let fixture: ComponentFixture<DropdownSitesComponent>;
let element: HTMLElement; let element: HTMLElement;
let siteService: SitesService; let siteService: SitesService;
@@ -167,7 +167,7 @@ describe('DropdownSitesComponent', () => {
}); });
it('should load custom sites when the "siteList" input property is given a value', async () => { it('should load custom sites when the "siteList" input property is given a value', async () => {
component.siteList = customSiteList; component.siteList = customSiteList as any;
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
@@ -246,7 +246,7 @@ describe('DropdownSitesComponent', () => {
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(component.selected).toBeUndefined(); expect(component.selected).toBeUndefined();
expect(component.loading).toBeFalsy(); expect(component.isLoading).toBeFalsy();
done(); done();
}); });
}); });
@@ -290,7 +290,7 @@ describe('DropdownSitesComponent', () => {
describe('No relations', () => { describe('No relations', () => {
beforeEach(() => { beforeEach(() => {
component.relations = []; component.relations = '';
authService = TestBed.inject(AuthenticationService); authService = TestBed.inject(AuthenticationService);
}); });
@@ -89,6 +89,10 @@ export class DropdownSitesComponent implements OnInit {
selected: SiteEntry = null; selected: SiteEntry = null;
MY_FILES_VALUE = '-my-'; MY_FILES_VALUE = '-my-';
get isLoading(): boolean {
return this.loading;
}
constructor( constructor(
private authService: AuthenticationService, private authService: AuthenticationService,
private sitesService: SitesService, private sitesService: SitesService,
@@ -161,7 +161,7 @@ export class FolderDialogComponent implements OnInit {
if (statusCode === 409) { if (statusCode === 409) {
errorMessage = 'CORE.MESSAGES.ERRORS.EXISTENT_FOLDER'; errorMessage = 'CORE.MESSAGES.ERRORS.EXISTENT_FOLDER';
} }
} catch (err) { } catch {
/* Do nothing, keep the original message */ /* Do nothing, keep the original message */
} }
@@ -20,7 +20,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { NodeDeleteDirective } from './node-delete.directive'; import { NodeDeleteDirective } from './node-delete.directive';
import { RedirectAuthService } from '@alfresco/adf-core'; import { RedirectAuthService } from '@alfresco/adf-core';
import { EMPTY, of } from 'rxjs'; import { EMPTY, of, Subscription } from 'rxjs';
import { CheckAllowableOperationDirective } from './check-allowable-operation.directive'; import { CheckAllowableOperationDirective } from './check-allowable-operation.directive';
@Component({ @Component({
@@ -73,10 +73,10 @@ describe('NodeDeleteDirective', () => {
let elementWithPermanentDelete: DebugElement; let elementWithPermanentDelete: DebugElement;
let component: TestComponent; let component: TestComponent;
let componentWithPermanentDelete: TestDeletePermanentComponent; let componentWithPermanentDelete: TestDeletePermanentComponent;
let deleteNodeSpy: any; let deleteNodeSpy: jasmine.Spy;
let disposableDelete: any; let disposableDelete: Subscription;
let deleteNodePermanentSpy: any; let deleteNodePermanentSpy: jasmine.Spy;
let purgeDeletedNodePermanentSpy: any; let purgeDeletedNodePermanentSpy: jasmine.Spy;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -38,7 +38,7 @@ describe('NodeRestoreDirective', () => {
let component: TestComponent; let component: TestComponent;
let trashcanApi: TrashcanApi; let trashcanApi: TrashcanApi;
let directiveInstance: NodeRestoreDirective; let directiveInstance: NodeRestoreDirective;
let restoreNodeSpy: any; let restoreNodeSpy: jasmine.Spy;
let translationService: TranslationService; let translationService: TranslationService;
beforeEach(() => { beforeEach(() => {
@@ -131,7 +131,7 @@ describe('NodeRestoreDirective', () => {
it('should notify on multiple fails', (done) => { it('should notify on multiple fails', (done) => {
const error = { message: '{ "error": {} }' }; const error = { message: '{ "error": {} }' };
directiveInstance.restore.subscribe((event: any) => { directiveInstance.restore.subscribe((event) => {
expect(event.message).toEqual('CORE.RESTORE_NODE.PARTIAL_PLURAL'); expect(event.message).toEqual('CORE.RESTORE_NODE.PARTIAL_PLURAL');
done(); done();
}); });
@@ -193,7 +193,7 @@ describe('NodeRestoreDirective', () => {
restoreNodeSpy.and.returnValue(Promise.reject(error)); restoreNodeSpy.and.returnValue(Promise.reject(error));
directiveInstance.restore.subscribe((event: any) => { directiveInstance.restore.subscribe((event) => {
expect(event.message).toEqual('CORE.RESTORE_NODE.LOCATION_MISSING'); expect(event.message).toEqual('CORE.RESTORE_NODE.LOCATION_MISSING');
done(); done();
}); });
@@ -205,7 +205,7 @@ describe('NodeRestoreDirective', () => {
}); });
it('should notify success when restore multiple nodes', (done) => { it('should notify success when restore multiple nodes', (done) => {
directiveInstance.restore.subscribe((event: any) => { directiveInstance.restore.subscribe((event) => {
expect(event.message).toEqual('CORE.RESTORE_NODE.PLURAL'); expect(event.message).toEqual('CORE.RESTORE_NODE.PLURAL');
done(); done();
@@ -52,7 +52,6 @@ import {
} from '../../mock'; } from '../../mock';
import { ContentTestingModule } from '../../testing/content.testing.module'; import { ContentTestingModule } from '../../testing/content.testing.module';
import { domSanitizerMock } from '../../testing/dom-sanitizer-mock'; import { domSanitizerMock } from '../../testing/dom-sanitizer-mock';
import { matIconRegistryMock } from '../../testing/mat-icon-registry-mock';
import { ImageResolver } from '../data/image-resolver.model'; import { ImageResolver } from '../data/image-resolver.model';
import { RowFilter } from '../data/row-filter.model'; import { RowFilter } from '../data/row-filter.model';
import { ShareDataRow } from '../data/share-data-row.model'; import { ShareDataRow } from '../data/share-data-row.model';
@@ -64,11 +63,16 @@ import { FileAutoDownloadComponent } from './file-auto-download/file-auto-downlo
import { DocumentListComponent } from './document-list.component'; import { DocumentListComponent } from './document-list.component';
import { CustomResourcesService, DocumentListService } from '../public-api'; import { CustomResourcesService, DocumentListService } from '../public-api';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { MatIconRegistry } from '@angular/material/icon';
const mockDialog = { const mockDialog = {
open: jasmine.createSpy('open') open: jasmine.createSpy('open')
}; };
export const matIconRegistryMock = {
addSvgIconInNamespace: () => {}
} as any as MatIconRegistry;
describe('DocumentList', () => { describe('DocumentList', () => {
let loader: HarnessLoader; let loader: HarnessLoader;
let documentList: DocumentListComponent; let documentList: DocumentListComponent;
@@ -430,7 +430,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
dataTable: DataTableComponent; dataTable: DataTableComponent;
actions: ContentActionModel[] = []; actions: ContentActionModel[] = [];
contextActionHandler: Subject<any> = new Subject(); contextActionHandler = new Subject();
data: ShareDataTableAdapter; data: ShareDataTableAdapter;
noPermission: boolean = false; noPermission: boolean = false;
selection = new Array<NodeEntry>(); selection = new Array<NodeEntry>();
@@ -1051,7 +1051,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
if (JSON.parse(err.message).error.statusCode === 403) { if (JSON.parse(err.message).error.statusCode === 403) {
this.noPermission = true; this.noPermission = true;
} }
} catch (error) { } catch {
/* empty */ /* empty */
} }
} }
@@ -57,17 +57,3 @@ export enum ContentActionTarget {
} }
export type ContentActionHandler = (obj: any, target?: any, permission?: string) => any; export type ContentActionHandler = (obj: any, target?: any, permission?: string) => any;
export class DocumentActionModel extends ContentActionModel {
constructor(json?: any) {
super(json);
this.target = 'document';
}
}
export class FolderActionModel extends ContentActionModel {
constructor(json?: any) {
super(json);
this.target = 'folder';
}
}
@@ -95,7 +95,7 @@ describe('FolderActionsService', () => {
it('should delete the folder node if there is the delete permission', () => { it('should delete the folder node if there is the delete permission', () => {
spyOn(documentListService, 'deleteNode').and.callFake( spyOn(documentListService, 'deleteNode').and.callFake(
() => () =>
new Observable<any>((observer) => { new Observable((observer) => {
observer.next(undefined); observer.next(undefined);
observer.complete(); observer.complete();
}) })
@@ -156,7 +156,7 @@ describe('FolderActionsService', () => {
it('should delete the folder node if there is the delete and others permission ', () => { it('should delete the folder node if there is the delete and others permission ', () => {
spyOn(documentListService, 'deleteNode').and.callFake( spyOn(documentListService, 'deleteNode').and.callFake(
() => () =>
new Observable<any>((observer) => { new Observable((observer) => {
observer.next(undefined); observer.next(undefined);
observer.complete(); observer.complete();
}) })
@@ -174,7 +174,7 @@ describe('FolderActionsService', () => {
it('should support deletion only folder node', () => { it('should support deletion only folder node', () => {
spyOn(documentListService, 'deleteNode').and.callFake( spyOn(documentListService, 'deleteNode').and.callFake(
() => () =>
new Observable<any>((observer) => { new Observable((observer) => {
observer.next(undefined); observer.next(undefined);
observer.complete(); observer.complete();
}) })
@@ -195,7 +195,7 @@ describe('FolderActionsService', () => {
it('should require node id to delete', () => { it('should require node id to delete', () => {
spyOn(documentListService, 'deleteNode').and.callFake( spyOn(documentListService, 'deleteNode').and.callFake(
() => () =>
new Observable<any>((observer) => { new Observable((observer) => {
observer.next(undefined); observer.next(undefined);
observer.complete(); observer.complete();
}) })
@@ -211,7 +211,7 @@ describe('FolderActionsService', () => {
it('should reload target upon node deletion', async () => { it('should reload target upon node deletion', async () => {
spyOn(documentListService, 'deleteNode').and.callFake( spyOn(documentListService, 'deleteNode').and.callFake(
() => () =>
new Observable<any>((observer) => { new Observable((observer) => {
observer.next(undefined); observer.next(undefined);
observer.complete(); observer.complete();
}) })
@@ -25,14 +25,13 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { MatButtonHarness } from '@angular/material/button/testing'; import { MatButtonHarness } from '@angular/material/button/testing';
import { ReplaySubject } from 'rxjs'; import { ReplaySubject } from 'rxjs';
import { UnitTestingUtils } from '@alfresco/adf-core';
import { MatCheckbox } from '@angular/material/checkbox'; import { MatCheckbox } from '@angular/material/checkbox';
import { By } from '@angular/platform-browser';
describe('SearchCheckListComponent', () => { describe('SearchCheckListComponent', () => {
let loader: HarnessLoader; let loader: HarnessLoader;
let fixture: ComponentFixture<SearchCheckListComponent>; let fixture: ComponentFixture<SearchCheckListComponent>;
let component: SearchCheckListComponent; let component: SearchCheckListComponent;
let unitTestingUtils: UnitTestingUtils;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -41,7 +40,6 @@ describe('SearchCheckListComponent', () => {
fixture = TestBed.createComponent(SearchCheckListComponent); fixture = TestBed.createComponent(SearchCheckListComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
loader = TestbedHarnessEnvironment.loader(fixture); loader = TestbedHarnessEnvironment.loader(fixture);
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
component.context = { component.context = {
queryFragments: {}, queryFragments: {},
@@ -149,7 +147,7 @@ describe('SearchCheckListComponent', () => {
]); ]);
fixture.detectChanges(); fixture.detectChanges();
const checkboxes = unitTestingUtils.getAllByDirective(MatCheckbox); const checkboxes = fixture.debugElement.queryAll(By.directive(MatCheckbox));
expect(checkboxes.length).toBe(2); expect(checkboxes.length).toBe(2);
expect(checkboxes.every((checkbox) => checkbox.componentInstance.labelPosition === 'after')).toBeTrue(); expect(checkboxes.every((checkbox) => checkbox.componentInstance.labelPosition === 'after')).toBeTrue();
}); });
@@ -43,7 +43,7 @@ describe('TagActionsComponent', () => {
} }
}; };
let component: any; let component: TagActionsComponent;
let fixture: ComponentFixture<TagActionsComponent>; let fixture: ComponentFixture<TagActionsComponent>;
let element: HTMLElement; let element: HTMLElement;
let tagService: TagService; let tagService: TagService;
@@ -90,7 +90,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
const deleteButton: any = element.querySelector('#tag_delete_test1'); const deleteButton = element.querySelector<HTMLButtonElement>('#tag_delete_test1');
deleteButton.click(); deleteButton.click();
expect(tagService.removeTag).toHaveBeenCalledWith('fake-node-id', '0ee933fa-57fc-4587-8a77-b787e814f1d2'); expect(tagService.removeTag).toHaveBeenCalledWith('fake-node-id', '0ee933fa-57fc-4587-8a77-b787e814f1d2');
}); });
@@ -102,7 +102,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
const addButton: any = element.querySelector('#add-tag'); const addButton = element.querySelector<HTMLButtonElement>('#add-tag');
expect(addButton.disabled).toEqual(true); expect(addButton.disabled).toEqual(true);
}); });
@@ -110,7 +110,7 @@ describe('TagActionsComponent', () => {
component.nodeId = 'fake-node-id'; component.nodeId = 'fake-node-id';
component.newTagName = 'test1'; component.newTagName = 'test1';
await component.error.subscribe((res) => { component.error.subscribe((res) => {
expect(res).toEqual('TAG.MESSAGES.EXIST'); expect(res).toEqual('TAG.MESSAGES.EXIST');
}); });
@@ -118,7 +118,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
const addButton: any = element.querySelector('#add-tag'); const addButton = element.querySelector<HTMLButtonElement>('#add-tag');
addButton.click(); addButton.click();
}); });
@@ -130,7 +130,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
const addButton: any = element.querySelector('#add-tag'); const addButton = element.querySelector<HTMLButtonElement>('#add-tag');
expect(addButton.disabled).toEqual(false); expect(addButton.disabled).toEqual(false);
}); });
}); });
@@ -790,7 +790,7 @@ describe('AlfrescoViewerComponent', () => {
}); });
it('should Click on close button hide the viewer', (done) => { it('should Click on close button hide the viewer', (done) => {
const closeButton: any = element.querySelector('.adf-viewer-close-button'); const closeButton = element.querySelector<HTMLButtonElement>('.adf-viewer-close-button');
closeButton.click(); closeButton.click();
fixture.detectChanges(); fixture.detectChanges();
@@ -300,7 +300,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
try { try {
const sharedLinkEntry = await this.sharedLinksApi.getSharedLink(this.sharedLinkId); const sharedLinkEntry = await this.sharedLinksApi.getSharedLink(this.sharedLinkId);
await this.setUpSharedLinkFile(sharedLinkEntry); await this.setUpSharedLinkFile(sharedLinkEntry);
} catch (error) { } catch {
this.invalidSharedLink.next(undefined); this.invalidSharedLink.next(undefined);
this.mimeType = 'invalid-link'; this.mimeType = 'invalid-link';
this.urlFileContent = 'invalid-file'; this.urlFileContent = 'invalid-file';
@@ -317,7 +317,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
await this.setUpNodeFile(this.nodeEntry.entry); await this.setUpNodeFile(this.nodeEntry.entry);
this.cdr.detectChanges(); this.cdr.detectChanges();
} }
} catch (error) { } catch {
this.urlFileContent = 'invalid-node'; this.urlFileContent = 'invalid-node';
} }
} }
@@ -392,14 +392,14 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf'); const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf');
return { url: urlFileContent, mimeType: 'application/pdf' }; return { url: urlFileContent, mimeType: 'application/pdf' };
} }
} catch (error) { } catch {
try { try {
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview'); const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview');
if (rendition.entry.status.toString() === 'CREATED') { if (rendition.entry.status.toString() === 'CREATED') {
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview'); const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview');
return { url: urlFileContent, mimeType: 'image/png' }; return { url: urlFileContent, mimeType: 'image/png' };
} }
} catch (renditionError) { } catch {
return null; return null;
} }
} }
@@ -313,7 +313,7 @@ export class AdfHttpClient implements ee.Emitter, JsApiHttpClient {
try { try {
document.cookie = 'CSRF-TOKEN=' + token + ';path=/'; document.cookie = 'CSRF-TOKEN=' + token + ';path=/';
} catch (err) { } catch {
/* continue regardless of error */ /* continue regardless of error */
} }
} }
@@ -58,7 +58,7 @@ describe('FlagsComponent', () => {
}); });
it('should update inputValue$ when onInputChange is called', (done) => { it('should update inputValue$ when onInputChange is called', (done) => {
(component as any).onInputChange('test'); component.onInputChange('test');
component.inputValue$.subscribe((value) => { component.inputValue$.subscribe((value) => {
expect(value).toBe('test'); expect(value).toBe('test');
done(); done();
@@ -67,12 +67,12 @@ describe('FlagsComponent', () => {
it('should clear inputValue when onClearInput is called', () => { it('should clear inputValue when onClearInput is called', () => {
component.inputValue = 'test'; component.inputValue = 'test';
(component as any).onClearInput(); component.onClearInput();
expect(component.inputValue).toBe(''); expect(component.inputValue).toBe('');
}); });
it('should filter flags when when onClearInput is called', (done) => { it('should filter flags when when onClearInput is called', (done) => {
(component as any).onInputChange('feature1'); component.onInputChange('feature1');
component.flags$.subscribe((flags) => { component.flags$.subscribe((flags) => {
expect(flags).toEqual([{ fictive: false, flag: 'feature1', value: true }]); expect(flags).toEqual([{ fictive: false, flag: 'feature1', value: true }]);
done(); done();
@@ -123,11 +123,11 @@ export class FlagsComponent {
this.featuresService.enable(value); this.featuresService.enable(value);
} }
protected onInputChange(text: string) { onInputChange(text: string) {
this.inputValue$.next(text); this.inputValue$.next(text);
} }
protected onClearInput() { onClearInput() {
this.inputValue = ''; this.inputValue = '';
this.inputValue$.next(''); this.inputValue$.next('');
} }
@@ -1,37 +0,0 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { StorageService } from '../common/services/storage.service';
import { AppConfigService, AppConfigValues } from './app-config.service';
@Injectable()
export class DebugAppConfigService extends AppConfigService {
constructor(private storage: StorageService) {
super();
}
get<T>(key: string, defaultValue?: T): T {
if (key === AppConfigValues.OAUTHCONFIG) {
return JSON.parse(this.storage.getItem(key)) || super.get<T>(key, defaultValue);
} else if (key === AppConfigValues.APPLICATION) {
return undefined;
} else {
return (this.storage.getItem(key) as any) || super.get<T>(key, defaultValue);
}
}
}
@@ -16,7 +16,6 @@
*/ */
export * from './app-config.service'; export * from './app-config.service';
export * from './debug-app-config.service';
export * from './app-config.pipe'; export * from './app-config.pipe';
export * from './app-config-storage-prefix.factory'; export * from './app-config-storage-prefix.factory';
@@ -76,20 +76,6 @@ export const clientRoles: IdentityRoleModel[] = [
export const mockJoinGroupRequest: IdentityJoinGroupRequestModel = { userId: 'mock-hser-id', groupId: 'mock-group-id', realm: 'mock-realm-name' }; export const mockJoinGroupRequest: IdentityJoinGroupRequestModel = { userId: 'mock-hser-id', groupId: 'mock-group-id', realm: 'mock-realm-name' };
export const mockGroup1 = {
id: 'mock-group-id-1',
name: 'Mock Group 1',
path: '/mock',
subGroups: []
} as IdentityGroupModel;
export const mockGroup2 = {
id: 'mock-group-id-2',
name: 'Mock Group 2',
path: '',
subGroups: []
} as IdentityGroupModel;
export const mockGroups = [ export const mockGroups = [
{ id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: [] } as IdentityGroupModel, { id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: [] } as IdentityGroupModel,
{ id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: [] } as IdentityGroupModel { id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: [] } as IdentityGroupModel
@@ -1,142 +0,0 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { mockIdentityGroups, mockIdentityGroupsCount, mockIdentityRoles } from './identity-group.mock';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { IdentityGroupServiceInterface } from '../interfaces/identity-group.interface';
import {
IdentityGroupModel,
IdentityGroupQueryResponse,
IdentityGroupQueryCloudRequestModel,
IdentityGroupSearchParam,
IdentityGroupCountModel
} from '../models/identity-group.model';
import { IdentityRoleModel } from '../models/identity-role.model';
Injectable({ providedIn: 'root' });
export class IdentityGroupServiceMock implements IdentityGroupServiceInterface {
getGroups(): Observable<IdentityGroupModel[]> {
return of(mockIdentityGroups);
}
getAvailableRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
getAssignedRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
assignRoles(_groupId: string, _roles: IdentityRoleModel[]): Observable<any> {
return of();
}
removeRoles(_groupId: string, _roles: IdentityRoleModel[]): Observable<any> {
return of();
}
getEffectiveRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
queryGroups(_requestQuery: IdentityGroupQueryCloudRequestModel): Observable<IdentityGroupQueryResponse> {
return of();
}
getTotalGroupsCount(): Observable<IdentityGroupCountModel> {
return of(mockIdentityGroupsCount);
}
createGroup(_newGroup: IdentityGroupModel): Observable<any> {
return of();
}
updateGroup(_groupId: string, _updatedGroup: IdentityGroupModel): Observable<any> {
return of();
}
deleteGroup(_groupId: string): Observable<any> {
return of();
}
findGroupsByName(searchParams: IdentityGroupSearchParam): Observable<IdentityGroupModel[]> {
if (searchParams.name === '') {
return of([]);
}
return of(mockIdentityGroups.filter((group) => group.name.toUpperCase().includes(searchParams.name.toUpperCase())));
}
getGroupRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
checkGroupHasRole(groupId: string, roleNames: string[]): Observable<boolean> {
return this.getGroupRoles(groupId).pipe(
map((groupRoles) => {
let hasRole = false;
if (groupRoles?.length > 0) {
roleNames.forEach((roleName: string) => {
const role = groupRoles.find(({ name }) => roleName === name);
if (role) {
hasRole = true;
return;
}
});
}
return hasRole;
})
);
}
getClientIdByApplicationName(_applicationName: string): Observable<string> {
return of('fake-client-id');
}
getClientRoles(groupId: string, _clientId: string): Observable<IdentityRoleModel[]> {
if (['mock-group-id-1', 'mock-group-id-2'].includes(groupId)) {
return of([{ id: 'mock-role-id', name: 'MOCK-ADMIN-ROLE' }]);
}
return of([{ id: 'mock-role-id', name: 'MOCK-USER-ROLE' }]);
}
checkGroupHasClientApp(groupId: string, clientId: string): Observable<boolean> {
return this.getClientRoles(groupId, clientId).pipe(map((response) => response && response.length > 0));
}
checkGroupHasAnyClientAppRole(groupId: string, clientId: string, roleNames: string[]): Observable<boolean> {
return this.getClientRoles(groupId, clientId).pipe(
map((clientRoles: any[]) => {
let hasRole = false;
if (clientRoles.length > 0) {
roleNames.forEach((roleName) => {
const role = clientRoles.find(({ name }) => name === roleName);
if (role) {
hasRole = true;
return;
}
});
}
return hasRole;
})
);
}
}
@@ -1,133 +0,0 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { mockGroups, mockIdentityGroups, roleMappingMock } from './identity-group.mock';
import { mockAssignedRoles, mockAvailableRoles, mockEffectiveRoles, mockIdentityUsers } from './identity-user.mock';
export const queryUsersMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockIdentityUsers)
}
};
export const createUserMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const updateUserMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const deleteUserMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const getInvolvedGroupsMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockGroups)
}
};
export const joinGroupMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const leaveGroupMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const getAvailableRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockAvailableRoles)
}
};
export const getAssignedRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockAssignedRoles)
}
};
export const getEffectiveRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockEffectiveRoles)
}
};
export const assignRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const removeRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const roleMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(roleMappingMock)
}
};
export const noRoleMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve([])
}
};
export const groupsMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockIdentityGroups)
}
};
export const createGroupMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const updateGroupMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const deleteGroupMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const applicationDetailsMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve([{ id: 'mock-app-id', name: 'mock-app-name' }])
}
};
@@ -60,10 +60,9 @@ describe('OidcAuthGuard', () => {
try { try {
await TestBed.runInInjectionContext(() => OidcAuthGuard(route, state)); await TestBed.runInInjectionContext(() => OidcAuthGuard(route, state));
expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/', { replaceUrl: true }); expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/', { replaceUrl: true });
} catch (error) { } catch {
fail('Expected no error to be thrown'); fail('Expected no error to be thrown');
} }
}); });
it('should throw an error if loginCallback fails and logout event is emitted', async () => { it('should throw an error if loginCallback fails and logout event is emitted', async () => {
@@ -89,7 +88,7 @@ describe('OidcAuthGuard', () => {
fakeLogoutSubject.next(); fakeLogoutSubject.next();
await runInInjectionContext; await runInInjectionContext;
expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/test-route', { replaceUrl: true }); expect(routerSpy.navigateByUrl).toHaveBeenCalledWith('/test-route', { replaceUrl: true });
} catch (error) { } catch {
fail('Expected no error to be thrown'); fail('Expected no error to be thrown');
} }
}); });
@@ -211,7 +211,7 @@ describe('RedirectAuthService', () => {
try { try {
await service.loginCallback(); await service.loginCallback();
fail('Expected to throw an error'); fail('Expected to throw an error');
} catch (error) { } catch {
expect(oauthServiceSpy.logOut).toHaveBeenCalledTimes(1); expect(oauthServiceSpy.logOut).toHaveBeenCalledTimes(1);
} }
}); });
@@ -281,7 +281,7 @@ describe('RedirectAuthService', () => {
try { try {
await service.loginCallback(); await service.loginCallback();
expect(oauthServiceSpy.logOut).not.toHaveBeenCalled(); expect(oauthServiceSpy.logOut).not.toHaveBeenCalled();
} catch (error) { } catch {
fail('Expected not to throw an error'); fail('Expected not to throw an error');
} }
}); });
@@ -135,7 +135,7 @@ export class StorageService {
storage.setItem(key, key); storage.setItem(key, key);
storage.removeItem(key, key); storage.removeItem(key, key);
return true; return true;
} catch (e) { } catch {
return false; return false;
} }
} }
File diff suppressed because it is too large Load Diff
@@ -2188,37 +2188,6 @@ export const mockSectionWithFields = {
colspan: 1 colspan: 1
}; };
export const mockFormWithSimpleSection = {
id: 'form-363114eb-35f6-40d0-9908-8bbbe776c3e6',
name: 'simplest section',
key: 'simplest-section-uzvc7',
description: '',
version: 0,
formDefinition: {
tabs: [],
fields: [
{
id: 'Group0wuwv7',
name: 'Group',
type: 'group',
tab: null,
params: {
hideHeader: false,
allowCollapse: false,
collapseByDefault: false
},
numberOfColumns: 1,
fields: {
1: [mockSectionWithFields]
}
}
],
outcomes: [],
metadata: {},
variables: []
}
};
export const mockSectionVisibilityForm = { export const mockSectionVisibilityForm = {
id: 'form-65e9f07c-44d9-4469-8f5d-74aba3bd7326', id: 'form-65e9f07c-44d9-4469-8f5d-74aba3bd7326',
name: 'section visibility', name: 'section visibility',
File diff suppressed because it is too large Load Diff
@@ -488,7 +488,7 @@ export class FormFieldModel extends FormWidgetModel {
let dateValue; let dateValue;
try { try {
dateValue = DateFnsUtils.parseDate(this.value, this.dateDisplayFormat); dateValue = DateFnsUtils.parseDate(this.value, this.dateDisplayFormat);
} catch (e) { } catch {
dateValue = new Date('error'); dateValue = new Date('error');
} }
@@ -24,11 +24,11 @@ import { FormService } from '../services/form.service';
import { ByPassFormRuleManager, FORM_RULES_MANAGER, FormRulesManager, formRulesManagerFactory } from './form-rules.model'; import { ByPassFormRuleManager, FORM_RULES_MANAGER, FormRulesManager, formRulesManagerFactory } from './form-rules.model';
class CustomRuleManager extends FormRulesManager<any> { class CustomRuleManager extends FormRulesManager<any> {
protected getRules() { getRules(): any {
return null; return null;
} }
protected handleRuleEvent(): void { handleRuleEvent(): void {
return; return;
} }
} }
@@ -67,8 +67,8 @@ describe('Form Rules', () => {
it('should send the form loaded event when initialized', () => { it('should send the form loaded event when initialized', () => {
const rulesManager = new CustomRuleManager(formService); const rulesManager = new CustomRuleManager(formService);
const getRulesSpy = spyOn<any>(rulesManager, 'getRules').and.returnValue({}); const getRulesSpy = spyOn(rulesManager, 'getRules').and.returnValue({});
const handleRuleEventSpy = spyOn<any>(rulesManager, 'handleRuleEvent'); const handleRuleEventSpy = spyOn(rulesManager, 'handleRuleEvent');
const formModel = new FormModel({ id: 'mock' }, {}, false); const formModel = new FormModel({ id: 'mock' }, {}, false);
const formEvent = new FormEvent(formModel); const formEvent = new FormEvent(formModel);
const event = new FormRulesEvent('formLoaded', formEvent); const event = new FormRulesEvent('formLoaded', formEvent);
@@ -82,8 +82,8 @@ describe('Form Rules', () => {
it('should not receive the form event when event has no form', () => { it('should not receive the form event when event has no form', () => {
const rulesManager = new CustomRuleManager(formService); const rulesManager = new CustomRuleManager(formService);
spyOn<any>(rulesManager, 'getRules').and.returnValue({}); spyOn(rulesManager, 'getRules').and.returnValue({});
const handleRuleEventSpy = spyOn<any>(rulesManager, 'handleRuleEvent'); const handleRuleEventSpy = spyOn(rulesManager, 'handleRuleEvent');
const formModel = new FormModel({ id: 'mock' }, {}, false); const formModel = new FormModel({ id: 'mock' }, {}, false);
const formEvent = new FormEvent(new FormModel(null)); const formEvent = new FormEvent(new FormModel(null));
const event = new FormRulesEvent('formLoaded', formEvent); const event = new FormRulesEvent('formLoaded', formEvent);
@@ -105,8 +105,8 @@ describe('Form Rules', () => {
beforeEach(() => { beforeEach(() => {
injector = TestBed.inject(Injector); injector = TestBed.inject(Injector);
rulesManager = formRulesManagerFactory<any>(injector); rulesManager = formRulesManagerFactory(injector);
getRulesSpy = spyOn<any>(rulesManager, 'getRules'); getRulesSpy = spyOn(rulesManager as any, 'getRules');
}); });
it('factory function should return bypass service', () => { it('factory function should return bypass service', () => {
-23
View File
@@ -15,31 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { DataColumn } from '../datatable/data/data-column.model';
import { mockPathInfos } from '../datatable/components/mocks/datatable.mock'; import { mockPathInfos } from '../datatable/components/mocks/datatable.mock';
export const getDataColumnMock = <T = unknown>(column: Partial<DataColumn<T>> = {}): DataColumn<T> => ({
id: 'columnId',
key: 'key',
type: 'text',
format: 'format',
sortable: false,
title: 'title',
srTitle: 'srTitle',
cssClass: 'cssClass',
template: undefined,
copyContent: false,
editable: false,
focus: false,
sortingKey: 'sortingKey',
header: undefined,
draggable: false,
resizable: true,
isHidden: false,
customData: undefined,
...column
});
export const textColumnRows = [{ firstname: 'John' }, { firstname: 'Henry' }, { firstname: 'David' }, { firstname: 'Thomas' }]; export const textColumnRows = [{ firstname: 'John' }, { firstname: 'Henry' }, { firstname: 'David' }, { firstname: 'Thomas' }];
export const dateColumnRows = [ export const dateColumnRows = [
@@ -19,12 +19,6 @@ import { FormModel, FormValues } from '../../form/components/widgets/core';
export const formTest = new FormModel({}); export const formTest = new FormModel({});
export const fakeTaskProcessVariableModels = [
{ id: 'TEST_VAR_1', type: 'string', value: 'test_value_1' },
{ id: 'TEST_VAR_2', type: 'string', value: 'test_value_2' },
{ id: 'TEST_VAR_3', type: 'string', value: 'test_value_3' }
];
export const formValues: FormValues = { export const formValues: FormValues = {
test_1: 'value_1', test_1: 'value_1',
test_2: 'value_2', test_2: 'value_2',
-4
View File
@@ -19,10 +19,6 @@ export * from './cookie.service.mock';
export * from './event.mock'; export * from './event.mock';
export * from './translation.service.mock'; export * from './translation.service.mock';
export * from './form/form.component.mock';
export * from './form/form-definition.mock';
export * from './form/form-definition-readonly.mock';
export * from './form/form-definition-visibility.mock';
export * from './form/form.service.mock'; export * from './form/form.service.mock';
export * from './form/widget-visibility.service.mock'; export * from './form/widget-visibility.service.mock';
+5 -42
View File
@@ -24,7 +24,7 @@ import { MatChipGridHarness, MatChipHarness, MatChipListboxHarness } from '@angu
import { MatButtonHarness } from '@angular/material/button/testing'; import { MatButtonHarness } from '@angular/material/button/testing';
import { MatIconHarness } from '@angular/material/icon/testing'; import { MatIconHarness } from '@angular/material/icon/testing';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { MatErrorHarness, MatFormFieldHarness } from '@angular/material/form-field/testing'; import { MatFormFieldHarness } from '@angular/material/form-field/testing';
import { MatInputHarness } from '@angular/material/input/testing'; import { MatInputHarness } from '@angular/material/input/testing';
import { MatAutocompleteHarness } from '@angular/material/autocomplete/testing'; import { MatAutocompleteHarness } from '@angular/material/autocomplete/testing';
import { ComponentFixture } from '@angular/core/testing'; import { ComponentFixture } from '@angular/core/testing';
@@ -34,7 +34,10 @@ import { MatSnackBarHarness } from '@angular/material/snack-bar/testing';
import { MatProgressBarHarness } from '@angular/material/progress-bar/testing'; import { MatProgressBarHarness } from '@angular/material/progress-bar/testing';
export class UnitTestingUtils { export class UnitTestingUtils {
constructor(private debugElement?: DebugElement, private loader?: HarnessLoader) { constructor(
private debugElement?: DebugElement,
private loader?: HarnessLoader
) {
this.debugElement = debugElement; this.debugElement = debugElement;
this.loader = loader; this.loader = loader;
} }
@@ -75,10 +78,6 @@ export class UnitTestingUtils {
return this.debugElement.query(By.directive(directive)); return this.debugElement.query(By.directive(directive));
} }
getAllByDirective(directive: Type<any>): DebugElement[] {
return this.debugElement.queryAll(By.directive(directive));
}
/** Perform actions */ /** Perform actions */
clickByCSS(selector: string): void { clickByCSS(selector: string): void {
@@ -243,10 +242,6 @@ export class UnitTestingUtils {
return this.loader.getHarness(MatIconHarness.with({ ancestor: selector })); return this.loader.getHarness(MatIconHarness.with({ ancestor: selector }));
} }
async getMatIconWithAncestorByCSSAndName(selector: string, name: string): Promise<MatIconHarness> {
return this.loader.getHarness(MatIconHarness.with({ ancestor: selector, name }));
}
async checkIfMatIconExistsWithAncestorByDataAutomationId(dataAutomationId: string): Promise<boolean> { async checkIfMatIconExistsWithAncestorByDataAutomationId(dataAutomationId: string): Promise<boolean> {
return this.loader.hasHarness(MatIconHarness.with({ ancestor: `[data-automation-id="${dataAutomationId}"]` })); return this.loader.hasHarness(MatIconHarness.with({ ancestor: `[data-automation-id="${dataAutomationId}"]` }));
} }
@@ -339,10 +334,6 @@ export class UnitTestingUtils {
return this.loader.getHarness(MatInputHarness); return this.loader.getHarness(MatInputHarness);
} }
async getMatInputByCSS(selector: string): Promise<MatInputHarness> {
return this.loader.getHarness(MatInputHarness.with({ selector }));
}
async getMatInputByDataAutomationId(dataAutomationId: string): Promise<MatInputHarness> { async getMatInputByDataAutomationId(dataAutomationId: string): Promise<MatInputHarness> {
return this.loader.getHarness(MatInputHarness.with({ selector: `[data-automation-id="${dataAutomationId}"]` })); return this.loader.getHarness(MatInputHarness.with({ selector: `[data-automation-id="${dataAutomationId}"]` }));
} }
@@ -360,14 +351,6 @@ export class UnitTestingUtils {
return this.loader.hasHarness(MatInputHarness); return this.loader.hasHarness(MatInputHarness);
} }
async checkIfMatInputExistsWithCSS(selector: string): Promise<boolean> {
return this.loader.hasHarness(MatInputHarness.with({ selector }));
}
async checkIfMatInputExistsWithDataAutomationId(dataAutomationId: string): Promise<boolean> {
return this.loader.hasHarness(MatInputHarness.with({ selector: `[data-automation-id="${dataAutomationId}"]` }));
}
async checkIfMatInputExistsWithPlaceholder(placeholder: string): Promise<boolean> { async checkIfMatInputExistsWithPlaceholder(placeholder: string): Promise<boolean> {
return this.loader.hasHarness(MatInputHarness.with({ placeholder })); return this.loader.hasHarness(MatInputHarness.with({ placeholder }));
} }
@@ -383,11 +366,6 @@ export class UnitTestingUtils {
await input.setValue(value); await input.setValue(value);
} }
async fillMatInputByCSS(selector: string, value: string): Promise<void> {
const input = await this.getMatInputByCSS(selector);
await input.setValue(value);
}
async fillMatInputByDataAutomationId(dataAutomationId: string, value: string): Promise<void> { async fillMatInputByDataAutomationId(dataAutomationId: string, value: string): Promise<void> {
const input = await this.getMatInputByDataAutomationId(dataAutomationId); const input = await this.getMatInputByDataAutomationId(dataAutomationId);
await input.setValue(value); await input.setValue(value);
@@ -409,11 +387,6 @@ export class UnitTestingUtils {
return input.getValue(); return input.getValue();
} }
async getMatInputValueByDataAutomationId(dataAutomationId: string): Promise<string> {
const input = await this.getMatInputByDataAutomationId(dataAutomationId);
return input.getValue();
}
async sendKeysToMatInput(keys: (string | TestKey)[]): Promise<void> { async sendKeysToMatInput(keys: (string | TestKey)[]): Promise<void> {
const input = await this.getMatInput(); const input = await this.getMatInput();
const host = await input.host(); const host = await input.host();
@@ -430,16 +403,6 @@ export class UnitTestingUtils {
return autocomplete.getOptions(); return autocomplete.getOptions();
} }
/** MatError related methods */
async getMatErrorByCSS(selector: string): Promise<MatErrorHarness> {
return this.loader.getHarness(MatErrorHarness.with({ selector }));
}
async getMatErrorByDataAutomationId(dataAutomationId: string): Promise<MatErrorHarness> {
return this.loader.getHarness(MatErrorHarness.with({ selector: `[data-automation-id="${dataAutomationId}"]` }));
}
/** MatTabGroup related methods */ /** MatTabGroup related methods */
async getSelectedTabFromMatTabGroup(): Promise<MatTabHarness> { async getSelectedTabFromMatTabGroup(): Promise<MatTabHarness> {
@@ -54,7 +54,7 @@ export class TranslateLoaderService implements TranslateLoader {
} }
providerRegistered(name: string): boolean { providerRegistered(name: string): boolean {
return !!this.providers.find((x) => x.name === name); return this.providers.some((x) => x.name === name);
} }
fetchLanguageFile(lang: string, component: ComponentTranslationModel, fallbackUrl?: string): Observable<void> { fetchLanguageFile(lang: string, component: ComponentTranslationModel, fallbackUrl?: string): Observable<void> {
@@ -75,7 +75,7 @@ export class TranslateLoaderService implements TranslateLoader {
return this.fetchLanguageFile(lang, component, url); return this.fetchLanguageFile(lang, component, url);
} }
} }
return throwError(`Failed to load ${translationUrl}`); return throwError(() => new Error(`Failed to load ${translationUrl}`));
}) })
); );
} }
@@ -85,13 +85,13 @@ export class TranslateLoaderService implements TranslateLoader {
if (!this.queue[lang]) { if (!this.queue[lang]) {
this.queue[lang] = []; this.queue[lang] = [];
} }
this.providers.forEach((component) => { for (const component of this.providers) {
if (!this.isComponentInQueue(lang, component.name)) { if (!this.isComponentInQueue(lang, component.name)) {
this.queue[lang].push(component.name); this.queue[lang].push(component.name);
observableBatch.push(this.fetchLanguageFile(lang, component)); observableBatch.push(this.fetchLanguageFile(lang, component));
} }
}); }
return observableBatch; return observableBatch;
} }
@@ -102,8 +102,8 @@ export class TranslateLoaderService implements TranslateLoader {
} }
} }
isComponentInQueue(lang: string, name: string) { isComponentInQueue(lang: string, name: string): boolean {
return !!(this.queue[lang] || []).find((x) => x === name); return (this.queue[lang] || []).some((x) => x === name);
} }
getFullTranslationJSON(lang: string): any { getFullTranslationJSON(lang: string): any {
@@ -144,8 +144,8 @@ export class TranslateLoaderService implements TranslateLoader {
return new Observable((observer) => { return new Observable((observer) => {
if (batch.length > 0) { if (batch.length > 0) {
forkJoin(batch).subscribe( forkJoin(batch).subscribe({
() => { next: () => {
const fullTranslation = this.getFullTranslationJSON(lang); const fullTranslation = this.getFullTranslationJSON(lang);
if (fullTranslation) { if (fullTranslation) {
observer.next(fullTranslation); observer.next(fullTranslation);
@@ -156,10 +156,10 @@ export class TranslateLoaderService implements TranslateLoader {
observer.complete(); observer.complete();
} }
}, },
() => { error: () => {
observer.error('Failed to load some resources'); observer.error('Failed to load some resources');
} }
); });
} else { } else {
const fullTranslation = this.getFullTranslationJSON(lang); const fullTranslation = this.getFullTranslationJSON(lang);
if (fullTranslation) { if (fullTranslation) {
@@ -88,31 +88,38 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
@HostListener('document:keydown', ['$event']) @HostListener('document:keydown', ['$event'])
onKeyDown(event: KeyboardEvent) { onKeyDown(event: KeyboardEvent) {
switch (event.key) { switch (event.key) {
case 'ArrowLeft': case 'ArrowLeft': {
event.preventDefault(); event.preventDefault();
this.cropper.move(-3, 0); this.cropper.move(-3, 0);
break; break;
case 'ArrowUp': }
case 'ArrowUp': {
event.preventDefault(); event.preventDefault();
this.cropper.move(0, -3); this.cropper.move(0, -3);
break; break;
case 'ArrowRight': }
case 'ArrowRight': {
event.preventDefault(); event.preventDefault();
this.cropper.move(3, 0); this.cropper.move(3, 0);
break; break;
case 'ArrowDown': }
case 'ArrowDown': {
event.preventDefault(); event.preventDefault();
this.cropper.move(0, 3); this.cropper.move(0, 3);
break; break;
case 'i': }
case 'i': {
this.zoomIn(); this.zoomIn();
break; break;
case 'o': }
case 'o': {
this.zoomOut(); this.zoomOut();
break; break;
case 'r': }
case 'r': {
this.rotateImage(); this.rotateImage();
break; break;
}
default: default:
} }
} }
@@ -132,7 +139,10 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
return Math.round(this.scale * 100) + '%'; return Math.round(this.scale * 100) + '%';
} }
constructor(private appConfigService: AppConfigService, private urlService: UrlService) { constructor(
private readonly appConfigService: AppConfigService,
private readonly urlService: UrlService
) {
this.initializeScaling(); this.initializeScaling();
} }
@@ -222,7 +232,7 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
this.cropper.clear(); this.cropper.clear();
this.cropper.reset(); this.cropper.reset();
this.cropper.setDragMode('move'); this.cropper.setDragMode('move');
this.scale = 1.0; this.scale = 1;
this.updateCanvasContainer(); this.updateCanvasContainer();
} }
@@ -27,7 +27,7 @@ import { UnitTestingUtils, provideCoreAuthTesting } from '../../../testing';
import { RenderingQueueServices } from '../../services/rendering-queue.services'; import { RenderingQueueServices } from '../../services/rendering-queue.services';
import { PdfThumbListComponent } from '../pdf-viewer-thumbnails/pdf-viewer-thumbnails.component'; import { PdfThumbListComponent } from '../pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
import { PDFJS_MODULE, PDFJS_VIEWER_MODULE, PdfViewerComponent } from './pdf-viewer.component'; import { PDFJS_MODULE, PDFJS_VIEWER_MODULE, PdfViewerComponent } from './pdf-viewer.component';
import pdfjsLibMock from '../mock/pdfjs-lib.mock'; import pdfjsLibraryMock from '../mock/pdfjs-lib.mock';
declare const pdfjsLib: any; declare const pdfjsLib: any;
@@ -441,7 +441,7 @@ describe('Test PdfViewer - User interaction', () => {
}, },
RenderingQueueServices, RenderingQueueServices,
{ provide: PDFJS_VIEWER_MODULE, useValue: pdfViewerSpy }, { provide: PDFJS_VIEWER_MODULE, useValue: pdfViewerSpy },
{ provide: PDFJS_MODULE, useValue: pdfjsLibMock } { provide: PDFJS_MODULE, useValue: pdfjsLibraryMock }
] ]
}); });
@@ -545,9 +545,9 @@ describe('ViewerComponent', () => {
keyCode: 27 keyCode: 27
} as KeyboardEventInit); } as KeyboardEventInit);
const dialogRef = dialog.open(DummyDialogComponent); const dialogReference = dialog.open(DummyDialogComponent);
dialogRef.afterClosed().subscribe(() => { dialogReference.afterClosed().subscribe(() => {
EventMock.keyDown(27); EventMock.keyDown(27);
fixture.detectChanges(); fixture.detectChanges();
expect(testingUtils.getByCSS('.adf-viewer-content')).toBeNull(); expect(testingUtils.getByCSS('.adf-viewer-content')).toBeNull();
@@ -245,7 +245,7 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
@Input() @Input()
nodeId: string = null; nodeId: string = null;
/** Original node mime type, should be provided when renditiona mime type is different. */ /** Original node mime type, should be provided when renditions mime type is different. */
@Input() @Input()
nodeMimeType: string = undefined; nodeMimeType: string = undefined;
@@ -60,7 +60,7 @@ export class ViewerExtensionDirective implements AfterContentInit {
isVisible(fileExtension: string): boolean { isVisible(fileExtension: string): boolean {
let supportedExtension: string; let supportedExtension: string;
if (this.supportedExtensions && this.supportedExtensions instanceof Array) { if (Array.isArray(this.supportedExtensions)) {
supportedExtension = this.supportedExtensions.find((extension) => extension.toLowerCase() === fileExtension); supportedExtension = this.supportedExtensions.find((extension) => extension.toLowerCase() === fileExtension);
} }
@@ -31,16 +31,16 @@ export class RenderingQueueServices {
FINISHED: 3 FINISHED: 3
}; };
CLEANUP_TIMEOUT: number = 30000; CLEANUP_TIMEOUT: number = 30_000;
pdfViewer: any = null; pdfViewer: any = null;
pdfThumbnailViewer: any = null; pdfThumbnailViewer: any = null;
onIdle: any = null; onIdle: any = null;
highestPriorityPage: any = null; highestPriorityPage: string | null = null;
idleTimeout: any = null; idleTimeout: any = null;
printing: any = false; printing: any = false;
isThumbnailViewEnabled: any = false; isThumbnailViewEnabled = false;
/** /**
* Set the instance of the PDF Viewer * Set the instance of the PDF Viewer
@@ -81,10 +81,8 @@ export class RenderingQueueServices {
return; return;
} }
// No pages needed rendering so check thumbnails. // No pages needed rendering so check thumbnails.
if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) { if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled && this.pdfThumbnailViewer.forceRendering()) {
if (this.pdfThumbnailViewer.forceRendering()) { return;
return;
}
} }
if (this.printing) { if (this.printing) {
@@ -106,11 +104,11 @@ export class RenderingQueueServices {
// 2 if last scrolled up page before the visible pages // 2 if last scrolled up page before the visible pages
const visibleViews = visible.views; const visibleViews = visible.views;
const numVisible = visibleViews.length; const numberVisible = visibleViews.length;
if (numVisible === 0) { if (numberVisible === 0) {
return false; return false;
} }
for (let i = 0; i < numVisible; ++i) { for (let i = 0; i < numberVisible; ++i) {
const view = visibleViews[i].view; const view = visibleViews[i].view;
if (!this.isViewFinished(view)) { if (!this.isViewFinished(view)) {
return view; return view;
@@ -180,8 +178,9 @@ export class RenderingQueueServices {
view.draw().then(continueRendering, continueRendering); view.draw().then(continueRendering, continueRendering);
break; break;
} }
default: default: {
break; break;
}
} }
return true; return true;
} }
@@ -53,7 +53,7 @@ export class ViewUtilService {
* @returns list of extensions * @returns list of extensions
*/ */
get externalExtensions(): string[] { get externalExtensions(): string[] {
return this.viewerExtensions.map((ext) => ext.fileExtension); return this.viewerExtensions.map((extension) => extension.fileExtension);
} }
constructor(private extensionService: AppExtensionService) {} constructor(private extensionService: AppExtensionService) {}
@@ -85,7 +85,7 @@ export class ViewUtilService {
const match = fileName.match(/\.([^./?#]+)($|\?|#)/); const match = fileName.match(/\.([^./?#]+)($|\?|#)/);
return match ? match[1] : null; return match ? match[1] : null;
} }
return null; return undefined;
} }
getViewerType(extension: string, mimeType: string, extensionsSupportedByTemplates?: string[]): string { getViewerType(extension: string, mimeType: string, extensionsSupportedByTemplates?: string[]): string {
@@ -104,7 +104,7 @@ export class ViewUtilService {
const editorTypes = Object.keys(this.mimeTypes); const editorTypes = Object.keys(this.mimeTypes);
for (const type of editorTypes) { for (const type of editorTypes) {
if (this.mimeTypes[type].indexOf(mimeType) >= 0) { if (this.mimeTypes[type].includes(mimeType)) {
return type; return type;
} }
} }
@@ -125,19 +125,19 @@ export class ViewUtilService {
return 'custom'; return 'custom';
} }
if (this.extensions.image.indexOf(extension) >= 0) { if (this.extensions.image.includes(extension)) {
return 'image'; return 'image';
} }
if (this.extensions.media.indexOf(extension) >= 0) { if (this.extensions.media.includes(extension)) {
return 'media'; return 'media';
} }
if (this.extensions.text.indexOf(extension) >= 0) { if (this.extensions.text.includes(extension)) {
return 'text'; return 'text';
} }
if (this.extensions.pdf.indexOf(extension) >= 0) { if (this.extensions.pdf.includes(extension)) {
return 'pdf'; return 'pdf';
} }
@@ -145,7 +145,7 @@ export class ViewUtilService {
} }
private isExternalViewer(): boolean { private isExternalViewer(): boolean {
return !!this.viewerExtensions.find((ext) => ext.fileExtension === '*'); return this.viewerExtensions.some((extension) => extension.fileExtension === '*');
} }
isCustomViewerExtension(extension: string, extensionsSupportedByTemplates?: string[]): boolean { isCustomViewerExtension(extension: string, extensionsSupportedByTemplates?: string[]): boolean {
@@ -156,7 +156,7 @@ export class ViewUtilService {
if (extension && extensions.length > 0) { if (extension && extensions.length > 0) {
extension = extension.toLowerCase(); extension = extension.toLowerCase();
return extensions.flat().indexOf(extension) >= 0; return extensions.flat().includes(extension);
} }
return false; return false;
+2 -2
View File
@@ -19,11 +19,11 @@ import 'zone.js';
import 'zone.js/testing'; import 'zone.js/testing';
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; import { platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
import pdfjsLibMock from './src/lib/viewer/components/mock/pdfjs-lib.mock'; import pdfjsLibraryMock from './src/lib/viewer/components/mock/pdfjs-lib.mock';
import { GlobalTestingModule } from './src/lib/testing/global-testing.module'; import { GlobalTestingModule } from './src/lib/testing/global-testing.module';
TestBed.initTestEnvironment(GlobalTestingModule, platformBrowserDynamicTesting(), { TestBed.initTestEnvironment(GlobalTestingModule, platformBrowserDynamicTesting(), {
teardown: { destroyAfterEach: true } teardown: { destroyAfterEach: true }
}); });
(window as any).pdfjsLib = pdfjsLibMock; (window as any).pdfjsLib = pdfjsLibraryMock;
+9 -1
View File
@@ -20,7 +20,15 @@ import { provideTranslations } from '@alfresco/adf-core';
import { ANALYTICS_PROCESS_DIRECTIVES } from './analytics-process/public-api'; import { ANALYTICS_PROCESS_DIRECTIVES } from './analytics-process/public-api';
import { DIAGRAM_DIRECTIVES } from './diagram/public-api'; import { DIAGRAM_DIRECTIVES } from './diagram/public-api';
/** @deprecated This module is deprecated and will be removed in a future release. */ /**
* @deprecated This module is deprecated and will be removed in a future release.
* Example:
* ```
* providers: [
* provideTranslations('adf-insights', 'assets/adf-insights')
* ]
* ```
*/
@NgModule({ @NgModule({
imports: [...ANALYTICS_PROCESS_DIRECTIVES, ...DIAGRAM_DIRECTIVES], imports: [...ANALYTICS_PROCESS_DIRECTIVES, ...DIAGRAM_DIRECTIVES],
exports: [...ANALYTICS_PROCESS_DIRECTIVES, ...DIAGRAM_DIRECTIVES] exports: [...ANALYTICS_PROCESS_DIRECTIVES, ...DIAGRAM_DIRECTIVES]
@@ -213,7 +213,7 @@ describe('AppListCloudComponent', () => {
customFixture.detectChanges(); customFixture.detectChanges();
await customFixture.whenStable(); await customFixture.whenStable();
const title: any = customFixture.nativeElement.querySelector('#custom-id'); const title = customFixture.nativeElement.querySelector('#custom-id');
expect(title.innerText).toBe('No Apps Found'); expect(title.innerText).toBe('No Apps Found');
}); });
}); });
@@ -28,7 +28,10 @@ import { RequestOptions } from '@alfresco/js-api';
export class AppsProcessCloudService { export class AppsProcessCloudService {
deployedApps: ApplicationInstanceModel[]; deployedApps: ApplicationInstanceModel[];
constructor(private adfHttpClient: AdfHttpClient, private appConfigService: AppConfigService) { constructor(
private readonly adfHttpClient: AdfHttpClient,
private readonly appConfigService: AppConfigService
) {
this.loadApps(); this.loadApps();
} }
@@ -48,11 +51,12 @@ export class AppsProcessCloudService {
} }
loadApps() { loadApps() {
const apps = this.appConfigService.get<any>('alfresco-deployed-apps', []); const apps = this.appConfigService.get<{ theme: string; icon: string }[]>('alfresco-deployed-apps', []);
apps.map((app) => { for (const app of apps) {
app.theme = app.theme ? app.theme : 'theme-1'; app.theme = app.theme ?? 'theme-1';
app.icon = app.icon ? app.icon : 'favorite'; app.icon = app.icon ?? 'favorite';
}); }
this.deployedApps = apps; this.deployedApps = apps;
} }
@@ -363,8 +363,8 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
}), }),
takeUntilDestroyed(this.destroyRef) takeUntilDestroyed(this.destroyRef)
) )
.subscribe( .subscribe({
(form) => { next: (form) => {
this.formCloudRepresentationJSON = form; this.formCloudRepresentationJSON = form;
this.formCloudRepresentationJSON.processVariables = this.data || []; this.formCloudRepresentationJSON.processVariables = this.data || [];
const parsedForm = this.parseForm(form); const parsedForm = this.parseForm(form);
@@ -374,10 +374,10 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
this.form.nodeId = '-my-'; this.form.nodeId = '-my-';
this.onFormLoaded(this.form); this.onFormLoaded(this.form);
}, },
(error) => { error: (error) => {
this.handleError(error); this.handleError(error);
} }
); });
} }
saveTaskForm() { saveTaskForm() {
@@ -385,12 +385,12 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
this.formCloudService this.formCloudService
.saveTaskForm(this.appName, this.taskId, this.processInstanceId, `${this.form.id}`, this.form.values) .saveTaskForm(this.appName, this.taskId, this.processInstanceId, `${this.form.id}`, this.form.values)
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe( .subscribe({
() => { next: () => {
this.onTaskSaved(this.form); this.onTaskSaved(this.form);
}, },
(error) => this.onTaskSavedError(error) error: (error) => this.onTaskSavedError(error)
); });
this.displayModeService.onSaveTask(this.id, this.displayMode, this.displayModeConfigurations); this.displayModeService.onSaveTask(this.id, this.displayMode, this.displayModeConfigurations);
} }
} }
@@ -420,12 +420,12 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
this.formCloudService this.formCloudService
.completeTaskForm(this.appName, this.taskId, this.processInstanceId, `${this.form.id}`, this.form.values, outcome, this.appVersion) .completeTaskForm(this.appName, this.taskId, this.processInstanceId, `${this.form.id}`, this.form.values, outcome, this.appVersion)
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe( .subscribe({
() => { next: () => {
this.onTaskCompleted(this.form); this.onTaskCompleted(this.form);
}, },
(error) => this.onTaskCompletedError(error) error: (error) => this.onTaskCompletedError(error)
); });
} }
} }
@@ -531,7 +531,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
} }
loadInjectedFieldValidators(injectedFieldValidators: FormFieldValidator[]): void { loadInjectedFieldValidators(injectedFieldValidators: FormFieldValidator[]): void {
if (injectedFieldValidators && injectedFieldValidators?.length) { if (Array.isArray(injectedFieldValidators) && injectedFieldValidators.length) {
this.fieldValidators = [...this.fieldValidators, ...injectedFieldValidators]; this.fieldValidators = [...this.fieldValidators, ...injectedFieldValidators];
} }
} }
@@ -268,7 +268,7 @@ export class GroupCloudComponent implements OnInit, OnChanges {
if (this.isPreselectedGroupInvalid(group, validationResult)) { if (this.isPreselectedGroupInvalid(group, validationResult)) {
this.invalidGroups.push(group); this.invalidGroups.push(group);
} }
} catch (error) { } catch {
this.invalidGroups.push(group); this.invalidGroups.push(group);
} }
} }
@@ -376,7 +376,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, AfterViewInit {
if (!this.equalsUsers(user, validationResult)) { if (!this.equalsUsers(user, validationResult)) {
this.invalidUsers.push(user); this.invalidUsers.push(user);
} }
} catch (error) { } catch {
this.invalidUsers.push(user); this.invalidUsers.push(user);
} }
} }
@@ -39,13 +39,14 @@ export const PROCESS_SERVICES_CLOUD_DIRECTIVES = [
* @deprecated this module is deprecated and will be removed in the future versions * @deprecated this module is deprecated and will be removed in the future versions
* *
* Instead, import the standalone components directly, or use the following provider API to replicate the behaviour: * Instead, import the standalone components directly, or use the following provider API to replicate the behaviour:
* * ```
* providers: [ * providers: [
* provideTranslations('adf-process-services-cloud', 'assets/adf-process-services-cloud') * provideTranslations('adf-process-services-cloud', 'assets/adf-process-services-cloud')
* provideCloudPreferences() * provideCloudPreferences()
* provideCloudFormRenderer(), * provideCloudFormRenderer(),
* { provide: TASK_LIST_CLOUD_TOKEN, useClass: TaskListCloudService } * { provide: TASK_LIST_CLOUD_TOKEN, useClass: TaskListCloudService }
* ] * ]
* ```
*/ */
@NgModule({ @NgModule({
imports: [ProcessCloudModule, TaskCloudModule, GroupCloudComponent, ...PROCESS_SERVICES_CLOUD_DIRECTIVES], imports: [ProcessCloudModule, TaskCloudModule, GroupCloudComponent, ...PROCESS_SERVICES_CLOUD_DIRECTIVES],
@@ -26,7 +26,6 @@ import {
DataColumnComponent, DataColumnComponent,
DataColumnListComponent, DataColumnListComponent,
DataRowEvent, DataRowEvent,
getDataColumnMock,
ObjectDataColumn, ObjectDataColumn,
ObjectDataRow, ObjectDataRow,
User, User,
@@ -46,6 +45,7 @@ import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing'; import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
import { provideCloudPreferences } from '../../../providers'; import { provideCloudPreferences } from '../../../providers';
import { getDataColumnMock } from '../../../testing/data-column.mock';
const fakeCustomSchema = [ const fakeCustomSchema = [
new ObjectDataColumn<ProcessListDataColumnCustomData>({ new ObjectDataColumn<ProcessListDataColumnCustomData>({
@@ -15,11 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { DataColumn, DataRow, getDataColumnMock } from '@alfresco/adf-core'; import { DataColumn, DataRow } from '@alfresco/adf-core';
import { getProcessInstanceVariableMock } from '../../../mock/process-instance-variable.mock'; import { getProcessInstanceVariableMock } from '../../../mock/process-instance-variable.mock';
import { ProcessListDataColumnCustomData, PROCESS_LIST_CUSTOM_VARIABLE_COLUMN } from '../../../models/data-column-custom-data'; import { ProcessListDataColumnCustomData, PROCESS_LIST_CUSTOM_VARIABLE_COLUMN } from '../../../models/data-column-custom-data';
import { ProcessInstanceCloudListViewModel } from '../models/perocess-instance-cloud-view.model'; import { ProcessInstanceCloudListViewModel } from '../models/perocess-instance-cloud-view.model';
import { ProcessListDatatableAdapter } from './process-list-datatable-adapter'; import { ProcessListDatatableAdapter } from './process-list-datatable-adapter';
import { getDataColumnMock } from '../../../testing/data-column.mock';
describe('ProcessListDatatableAdapter', () => { describe('ProcessListDatatableAdapter', () => {
it('should get proepr type for column', () => { it('should get proepr type for column', () => {
@@ -15,21 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { FormFieldModel, FormFieldValidator } from '@alfresco/adf-core';
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model'; import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model'; import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model'; import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
export class MockFormFieldValidator implements FormFieldValidator {
isSupported(_field: FormFieldModel): boolean {
return true;
}
validate(_field: FormFieldModel): boolean {
return true;
}
}
export const fakeProcessInstance: ProcessInstanceCloud = { export const fakeProcessInstance: ProcessInstanceCloud = {
appName: 'simple-app', appName: 'simple-app',
appVersion: '1', appVersion: '1',
@@ -16,11 +16,11 @@
*/ */
import { getProcessInstanceVariableMock } from '../mock/process-instance-variable.mock'; import { getProcessInstanceVariableMock } from '../mock/process-instance-variable.mock';
import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data'; import { ProcessListDataColumnCustomData } from '../models/data-column-custom-data';
import { ProcessInstanceVariable } from '../models/process-instance-variable.model'; import { ProcessInstanceVariable } from '../models/process-instance-variable.model';
import { VariableMapperService } from './variable-mapper.sevice'; import { VariableMapperService } from './variable-mapper.sevice';
import { DataColumn, getDataColumnMock } from '@alfresco/adf-core'; import { DataColumn } from '@alfresco/adf-core';
import { getDataColumnMock } from '../testing/data-column.mock';
describe('VariableMapperService', () => { describe('VariableMapperService', () => {
let service: VariableMapperService; let service: VariableMapperService;
@@ -15,7 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { DataColumn, DataRow, getDataColumnMock } from '@alfresco/adf-core'; import { DataColumn, DataRow } from '@alfresco/adf-core';
import { getDataColumnMock } from '../../../../../testing/data-column.mock';
import { ProcessListDataColumnCustomData, PROCESS_LIST_CUSTOM_VARIABLE_COLUMN } from '../../../../../models/data-column-custom-data'; import { ProcessListDataColumnCustomData, PROCESS_LIST_CUSTOM_VARIABLE_COLUMN } from '../../../../../models/data-column-custom-data';
import { TasksListDatatableAdapter } from './task-list-datatable-adapter'; import { TasksListDatatableAdapter } from './task-list-datatable-adapter';
import { TaskInstanceCloudListViewModel } from '../../../models/task-cloud-view.model'; import { TaskInstanceCloudListViewModel } from '../../../models/task-cloud-view.model';
@@ -15,8 +15,26 @@
* limitations under the License. * limitations under the License.
*/ */
import { MatIconRegistry } from '@angular/material/icon'; import { DataColumn } from '@alfresco/adf-core';
export const matIconRegistryMock = { export const getDataColumnMock = <T = unknown>(column: Partial<DataColumn<T>> = {}): DataColumn<T> => ({
addSvgIconInNamespace: () => {} id: 'columnId',
} as any as MatIconRegistry; key: 'key',
type: 'text',
format: 'format',
sortable: false,
title: 'title',
srTitle: 'srTitle',
cssClass: 'cssClass',
template: undefined,
copyContent: false,
editable: false,
focus: false,
sortingKey: 'sortingKey',
header: undefined,
draggable: false,
resizable: true,
isHidden: false,
customData: undefined,
...column
});
@@ -269,7 +269,7 @@ describe('AppsListComponent', () => {
customFixture.detectChanges(); customFixture.detectChanges();
await customFixture.whenStable(); await customFixture.whenStable();
const title: any = customFixture.debugElement.queryAll(By.css('#custom-id')); const title = customFixture.debugElement.queryAll(By.css('#custom-id'));
expect(title.length).toBe(1); expect(title.length).toBe(1);
expect(title[0].nativeElement.innerText).toBe('No Apps'); expect(title[0].nativeElement.innerText).toBe('No Apps');
}); });
@@ -29,9 +29,9 @@ import {
FormService, FormService,
WidgetVisibilityService, WidgetVisibilityService,
ContainerModel, ContainerModel,
fakeForm,
NoopAuthModule NoopAuthModule
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { fakeForm } from './form.component.mock';
import { NodeMetadata, NodesApiService } from '@alfresco/adf-content-services'; import { NodeMetadata, NodesApiService } from '@alfresco/adf-content-services';
import { FormComponent } from './form.component'; import { FormComponent } from './form.component';
import { ProcessFormRenderingService } from './process-form-rendering.service'; import { ProcessFormRenderingService } from './process-form-rendering.service';
@@ -19,15 +19,10 @@ import { SimpleChange } from '@angular/core';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { import { formDefinitionDropdownField, formDefinitionTwoTextFields, formDefinitionRequiredField } from './form-definition.mock';
formDefinitionDropdownField, import { formDefVisibilityFieldDependsOnNextOne, formDefVisibilitiFieldDependsOnPreviousOne } from './form-definition-visibility.mock';
formDefinitionTwoTextFields, import { formReadonlyTwoTextFields } from './form-definition-readonly.mock';
formDefinitionRequiredField, import { FormRenderingService } from '@alfresco/adf-core';
formDefVisibilityFieldDependsOnNextOne,
formDefVisibilitiFieldDependsOnPreviousOne,
formReadonlyTwoTextFields,
FormRenderingService
} from '@alfresco/adf-core';
import { FormComponent } from './form.component'; import { FormComponent } from './form.component';
import { TaskService } from './services/task.service'; import { TaskService } from './services/task.service';
import { TaskFormService } from './services/task-form.service'; import { TaskFormService } from './services/task-form.service';
@@ -32,6 +32,12 @@ import { TextEditorComponent } from '../text/text.editor';
import { ErrorWidgetComponent } from '@alfresco/adf-core'; import { ErrorWidgetComponent } from '@alfresco/adf-core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
export interface RowEditorReturnType {
table: DynamicTableModel;
row: DynamicTableRow;
column: DynamicTableColumn;
}
@Component({ @Component({
selector: 'row-editor', selector: 'row-editor',
imports: [ imports: [
@@ -59,10 +65,10 @@ export class RowEditorComponent {
column: DynamicTableColumn; column: DynamicTableColumn;
@Output() @Output()
save: EventEmitter<any> = new EventEmitter<any>(); save = new EventEmitter<RowEditorReturnType>();
@Output() @Output()
cancel: EventEmitter<any> = new EventEmitter<any>(); cancel = new EventEmitter<RowEditorReturnType>();
validationSummary: DynamicRowValidationSummary; validationSummary: DynamicRowValidationSummary;
@@ -74,7 +74,7 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
groupId: number; groupId: number;
searchTerm = new UntypedFormControl(); searchTerm = new UntypedFormControl();
searchTerms$: Observable<any> = this.searchTerm.valueChanges; searchTerms$ = this.searchTerm.valueChanges;
users$: Observable<LightUserRepresentation[]> = this.searchTerms$.pipe( users$: Observable<LightUserRepresentation[]> = this.searchTerms$.pipe(
distinctUntilChanged(), distinctUntilChanged(),
@@ -92,7 +92,10 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
}) })
); );
constructor(public formService: FormService, public peopleProcessService: PeopleProcessService) { constructor(
public formService: FormService,
public peopleProcessService: PeopleProcessService
) {
super(formService); super(formService);
} }
@@ -307,7 +307,7 @@ export class ProcessService {
try { try {
return datePipe.transform(value, dateFormat); return datePipe.transform(value, dateFormat);
} catch (err) { } catch {
return ''; return '';
} }
} }
@@ -28,6 +28,17 @@ import { FORM_DIRECTIVES } from './form';
import { TASK_COMMENTS_DIRECTIVES } from './task-comments'; import { TASK_COMMENTS_DIRECTIVES } from './task-comments';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
/**
* @deprecated use provider api instead, for example:
* ```
* providers: [
* provideTranslations('adf-process-services', 'assets/adf-process-services'),
* { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { floatLabel: 'never' } }
* FormRenderingService,
* { provide: FormRenderingService, useClass: ProcessFormRenderingService }
* ]
* ```
*/
@NgModule({ @NgModule({
imports: [ imports: [
...PROCESS_COMMENTS_DIRECTIVES, ...PROCESS_COMMENTS_DIRECTIVES,
@@ -759,7 +759,7 @@ describe('TaskFormComponent', () => {
component.taskId = 'mock-task-id'; component.taskId = 'mock-task-id';
component.error.subscribe((error: any) => { component.error.subscribe((error) => {
expect(error).toEqual(mockError); expect(error).toEqual(mockError);
done(); done();
}); });
@@ -184,7 +184,7 @@ describe('TaskHeaderComponent', () => {
await fixture.whenStable(); await fixture.whenStable();
const datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-dueDate"]`)); const datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-dueDate"]`));
expect(datePicker).toBeNull('Datepicker should NOT be in DOM'); expect(datePicker).toBeNull();
}); });
it('should set editable to true if the task has not completed yet', async () => { it('should set editable to true if the task has not completed yet', async () => {