chore: eslint fixes for @typescript-eslint/no-explicit-any (#11672)

This commit is contained in:
Denys Vuika
2026-02-23 13:11:44 +00:00
committed by GitHub
parent 9be5eae00c
commit 303a9efb3e
40 changed files with 269 additions and 178 deletions

View File

@@ -145,6 +145,14 @@ module.exports = {
'no-multiple-empty-lines': 'error',
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': ['off', { ignoreDeclarationMerge: true }],
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_'
}
],
'no-return-await': 'error',
'rxjs/no-create': 'error',
'rxjs/no-subject-unsubscribe': 'error',

View File

@@ -92,8 +92,8 @@ See the [Custom layout](#custom-layout) section for full details of all availabl
| showRightSidebar | `boolean` | false | Toggles right sidebar visibility. Requires `allowRightSidebar` to be set to `true`. |
| showToolbar | `boolean` | true | Hide or show the toolbar |
| showViewer | `boolean` | true | Hide or show the viewer |
| sidebarLeftTemplate | `TemplateRef<any>` | null | The template for the left sidebar. The template context contains the loaded node data. |
| sidebarRightTemplate | `TemplateRef<any>` | null | The template for the right sidebar. The template context contains the loaded node data. |
| sidebarLeftTemplate | `TemplateRef<unknown>` | null | The template for the left sidebar. The template context contains the loaded node data. |
| sidebarRightTemplate | `TemplateRef<unknown>` | null | The template for the right sidebar. The template context contains the loaded node data. |
| versionId | `string` | null | Version Id of the file to load. |
### Events

View File

@@ -236,7 +236,7 @@ Next in your component you need to get a reference of created template
```ts
@ViewChild('viewerExtensions')
viewerTemplateExtensions: TemplateRef<any>;
viewerTemplateExtensions: TemplateRef<unknown>;
```
and pass it via `viewerTemplateExtensions` input:

View File

@@ -53,8 +53,8 @@ With icon:
```
```ts
@ViewChild('contentDialogTemplate') contentDialogTemplate: TemplateRef<any>;
@ViewChild('actionsDialogTemplate') actionsDialogTemplate: TemplateRef<any>;
@ViewChild('contentDialogTemplate') contentDialogTemplate: TemplateRef<unknown>;
@ViewChild('actionsDialogTemplate') actionsDialogTemplate: TemplateRef<unknown>;
constructor(private dialog: MatDialog) {}

View File

@@ -68,7 +68,7 @@ interface DataColumn {
title?: string;
srTitle?: string;
cssClass?: string;
template?: TemplateRef<any>;
template?: TemplateRef<unknown>;
formatTooltip?: Function;
focus?: boolean;
}

View File

@@ -21,9 +21,9 @@ interface DialogData {
isCloseButtonHidden?: boolean;
isCancelButtonHidden?: boolean;
dialogSize?: DialogSizes;
contentTemplate?: TemplateRef<any>;
actionsTemplate?: TemplateRef<any>;
descriptionTemplate?: TemplateRef<any>;
contentTemplate?: TemplateRef<unknown>;
actionsTemplate?: TemplateRef<unknown>;
descriptionTemplate?: TemplateRef<unknown>;
headerIcon?: string;
additionalActionButtons?: AdditionalDialogActionButton[];
componentData?: any;
@@ -46,9 +46,9 @@ interface DialogData {
| dialogSize | `DialogSize` | `Medium` | Set dialog size. Can be `Large`, `Medium`, `Alert`. (optional) |
| contentText | `string` | | Inserts a content text. (optional) |
| contentComponent | `Type<any>` | | Inserts a content component. (optional) |
| contentTemplate | `TemplateRef<any>` | | Inserts a content template. (optional) |
| actionsTemplate | `TemplateRef<any>` | | Inserts a template styled on the left. Should be used for additional `mat-button` style buttons. (optional) |
| descriptionTemplate | `TemplateRef<any>` | | Inserts a description template. (optional) |
| contentTemplate | `TemplateRef<unknown>` | | Inserts a content template. (optional) |
| actionsTemplate | `TemplateRef<unknown>` | | Inserts a template styled on the left. Should be used for additional `mat-button` style buttons. (optional) |
| descriptionTemplate | `TemplateRef<unknown>` | | Inserts a description template. (optional) |
| additionalActionButtons | `AdditionalDialogActionButton[]` | | Inserts additional base-styled buttons into the action bar on the left. (optional) |
| componentData | `any` | | Data that injected in contentComponent. (optional) |
| dataOnConfirm$ | `Subject<any>` | | Data to be passed on confirm action after dialog closed. (optional) |

View File

@@ -18,10 +18,16 @@
import { Injectable, inject } from '@angular/core';
import { from, Observable, throwError, Subject } from 'rxjs';
import { catchError, map, switchMap, filter, take } from 'rxjs/operators';
import { RepositoryInfo, SystemPropertiesRepresentation, DiscoveryApi, AboutApi, SystemPropertiesApi } from '@alfresco/js-api';
import {
RepositoryInfo,
SystemPropertiesRepresentation,
DiscoveryApi,
AboutApi,
SystemPropertiesApi,
BpmProductVersionModel
} from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { BpmProductVersionModel, AuthenticationService } from '@alfresco/adf-core';
import { AuthenticationService } from '@alfresco/adf-core';
@Injectable({
providedIn: 'root'
@@ -66,24 +72,21 @@ export class DiscoveryApiService {
}
/**
* @deprecated since 8.3.0 this method is no longer used, and will be removed in the next major release.
* Gets product information for Process Services.
*
* @returns ProductVersionModel containing product details
*/
getBpmProductInfo(): Observable<BpmProductVersionModel> {
const aboutApi = new AboutApi(this.alfrescoApiService.getInstance());
return from(aboutApi.getAppVersion()).pipe(
map((res) => new BpmProductVersionModel(res)),
catchError((err) => throwError(err))
);
return from(aboutApi.getAppVersion());
}
getBPMSystemProperties(): Observable<SystemPropertiesRepresentation> {
const systemPropertiesApi = new SystemPropertiesApi(this.alfrescoApiService.getInstance());
return from(systemPropertiesApi.getProperties()).pipe(
map((res: any) => {
map((res) => {
if ('string' === typeof res) {
throw new Error('Not valid response');
}

View File

@@ -207,7 +207,6 @@ describe('BaseQueryBuilderService', () => {
expect(service.getUserFacetBuckets('field1').length).toBe(0);
expect(service.getUserFacetBuckets('field2').length).toBe(0);
});
});
describe('buildQuery', () => {
@@ -332,12 +331,12 @@ describe('BaseQueryBuilderService', () => {
expect(errorSpy).toHaveBeenCalledWith(mockError);
expect(executedSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
list: jasmine.objectContaining({
pagination: { totalItems: 0 },
entries: []
})
})
jasmine.objectContaining({
list: jasmine.objectContaining({
pagination: { totalItems: 0 },
entries: []
})
})
);
});
@@ -423,9 +422,7 @@ describe('BaseQueryBuilderService', () => {
spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve({ list: { entries: [] } } as ResultSetPaging));
let callCount = 0;
service.searchForms.pipe(skip(1)).subscribe((forms) => {
callCount++;
expect(forms[1].selected).toBe(true);
expect(forms[0].selected).toBe(false);
done();
@@ -446,7 +443,7 @@ describe('BaseQueryBuilderService', () => {
it('should call execute when updating configuration', async () => {
spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
spyOn(service.searchApi, 'search').and.returnValue(Promise.resolve({ list: { entries: [] } } as ResultSetPaging));
spyOn(service, 'execute')
spyOn(service, 'execute');
service.userQuery = 'test';
service.updateSelectedConfiguration('config-2');

View File

@@ -15,7 +15,6 @@
* limitations under the License.
*/
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { IFeaturesService, FlagChangeset } from '../interfaces/features.interface';

View File

@@ -91,7 +91,6 @@ export class StorageFeaturesService implements IFeaturesService, IWritableFeatur
}
removeFlag(key: string): void {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [key]: _, ...flags } = this.currentFlagState;
this.flags.next(flags);
}

View File

@@ -27,7 +27,6 @@ describe('StoragePrefixFactory', () => {
it('should get prefix set in app.config.json', () => {
const appConfigPrefix = 'prefix-from-app-config-json';
const appConfigService: TestAppConfigService = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
select(_property: string) {
return of(appConfigPrefix);
}
@@ -48,7 +47,6 @@ describe('StoragePrefixFactory', () => {
it('should work with NO prefix set in app.config.json', () => {
const appConfigPrefix = undefined;
const appConfigService: TestAppConfigService = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
select(_property: string) {
return of(appConfigPrefix);
}
@@ -69,7 +67,6 @@ describe('StoragePrefixFactory', () => {
it('should return prefix from provided factory, when NO prefix is set in app.config.json', () => {
const appConfigPrefix = undefined;
const appConfigService: TestAppConfigService = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
select(_property: string) {
return of(appConfigPrefix);
}
@@ -100,7 +97,6 @@ describe('StoragePrefixFactory', () => {
const appConfigPrefix = 'prefix-from-app-config-json';
const appConfigService: TestAppConfigService = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
select(_property: string) {
return of(appConfigPrefix);
}

View File

@@ -1,34 +0,0 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export class BpmProductVersionModel {
edition: string;
majorVersion: string;
revisionVersion: string;
minorVersion: string;
type: string;
constructor(obj?: any) {
if (obj) {
this.edition = obj.edition || null;
this.majorVersion = obj.majorVersion || null;
this.revisionVersion = obj.revisionVersion || null;
this.minorVersion = obj.minorVersion || null;
this.type = obj.type || null;
}
}
}

View File

@@ -15,7 +15,6 @@
* limitations under the License.
*/
export * from './product-version.model';
export * from './comment.model';
export * from './pagination.model';
export * from './request-pagination.model';

View File

@@ -25,12 +25,12 @@ import { TranslationService } from '../translation/translation.service';
export class FileSizePipe implements PipeTransform {
private readonly translation = inject(TranslationService);
transform(paramByte: any, decimals: number = 2): string {
transform(paramByte: number | string | null, decimals: number = 2): string {
if (paramByte == null) {
return '';
}
const bytes = parseInt(paramByte, 10);
const bytes = typeof paramByte === 'number' ? paramByte : parseInt(paramByte as string, 10);
if (isNaN(bytes)) {
return '';
}

View File

@@ -40,7 +40,7 @@ describe('SearchTextInputComponent', () => {
debugElement = fixture.debugElement;
testingUtils = new UnitTestingUtils(debugElement);
userPreferencesService = TestBed.inject(UserPreferencesService);
component.focusListener = new Subject<any>();
component.focusListener = new Subject();
});
afterEach(() => {

View File

@@ -91,7 +91,7 @@ describe('TranslationService', () => {
const mockLanguages = spyOnProperty(window, 'navigator').and.returnValue({
language: 'en-GB',
languages: returnedLanguages
} as any);
} as unknown as Navigator);
expect(translationService.getLocale()).toBe('fr-FR');
expect(mockLanguages).toHaveBeenCalled();
@@ -102,7 +102,7 @@ describe('TranslationService', () => {
const mockLanguages = spyOnProperty(window, 'navigator').and.returnValue({
language: 'de-DE',
languages: []
} as any);
} as unknown as Navigator);
expect(translationService.getLocale()).toBe('de-DE');
expect(mockLanguages).toHaveBeenCalled();

View File

@@ -74,11 +74,11 @@ export class ImgViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
// eslint-disable-next-line @angular-eslint/no-output-native
@Output()
error = new EventEmitter<any>();
error = new EventEmitter<void>();
// eslint-disable-next-line @angular-eslint/no-output-native
@Output()
submit = new EventEmitter<any>();
submit = new EventEmitter<Blob>();
@Output()
isSaving = new EventEmitter<boolean>();

View File

@@ -48,7 +48,7 @@ export class MediaPlayerComponent implements OnChanges {
tracks: Track[] = [];
@Output()
error = new EventEmitter<any>();
error = new EventEmitter<Event>();
@Output()
canPlay = new EventEmitter<void>();
@@ -66,7 +66,7 @@ export class MediaPlayerComponent implements OnChanges {
}
}
onMediaPlayerError(event: any) {
onMediaPlayerError(event: Event) {
this.error.emit(event);
}
}

View File

@@ -19,7 +19,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { PdfPasswordDialogComponent } from './pdf-viewer-password-dialog';
declare const pdfjsLib: any;
declare const pdfjsLib: { PasswordResponses: { NEED_PASSWORD: number; INCORRECT_PASSWORD: number } };
describe('PdfPasswordDialogComponent', () => {
let component: PdfPasswordDialogComponent;

View File

@@ -25,7 +25,7 @@ import { MatInputModule } from '@angular/material/input';
import { TranslatePipe } from '@ngx-translate/core';
import { IconModule } from '../../../icon/icon.module';
declare const pdfjsLib: any;
declare const pdfjsLib: { PasswordResponses: { NEED_PASSWORD: number; INCORRECT_PASSWORD: number } };
@Component({
selector: 'adf-pdf-viewer-password-dialog',

View File

@@ -28,7 +28,7 @@ describe('PdfThumbComponent', () => {
const width = 91;
const height = 119;
const page = {
id: 'pageId',
id: 1,
getPage: jasmine.createSpy('getPage').and.returnValue(
Promise.resolve({
getViewport: () => ({ width, height }),

View File

@@ -20,6 +20,7 @@ import { AsyncPipe, NgIf } from '@angular/common';
import { Component, ElementRef, Input, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { TranslatePipe } from '@ngx-translate/core';
import { PdfThumbnailPage } from '../pdf-viewer/pdf-viewer.component';
@Component({
selector: 'adf-pdf-thumb',
@@ -33,7 +34,7 @@ export class PdfThumbComponent implements OnInit, FocusableOption {
private readonly element = inject(ElementRef);
@Input()
page: any = null;
page: PdfThumbnailPage = null;
image$: Promise<string>;

View File

@@ -19,8 +19,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PdfThumbListComponent } from './pdf-viewer-thumbnails.component';
import { UnitTestingUtils } from '../../../testing';
import { DOWN_ARROW, ESCAPE, UP_ARROW } from '@angular/cdk/keycodes';
import { PDFViewer } from 'pdfjs-dist/web/pdf_viewer.mjs';
declare const pdfjsViewer: any;
declare const pdfjsViewer: { EventBus: new () => { dispatch: (event: string, data: unknown) => void } };
describe('PdfThumbListComponent', () => {
let fixture: ComponentFixture<PdfThumbListComponent>;
@@ -77,7 +78,7 @@ describe('PdfThumbListComponent', () => {
fixture = TestBed.createComponent(PdfThumbListComponent);
testingUtils = new UnitTestingUtils(fixture.debugElement);
component = fixture.componentInstance;
component.pdfViewer = viewerMock;
component.pdfViewer = viewerMock as unknown as PDFViewer;
// provide scrollable container
fixture.nativeElement.style.display = 'block';

View File

@@ -36,6 +36,9 @@ import {
inject
} from '@angular/core';
import { delay } from 'rxjs/operators';
import { PDFViewer } from 'pdfjs-dist/web/pdf_viewer.mjs';
import { PDFPageProxy } from 'pdfjs-dist/types/src/display/api';
import { PageChangingEvent, PdfThumbnailPage } from '../pdf-viewer/pdf-viewer.component';
import { PdfThumbComponent } from '../pdf-viewer-thumb/pdf-viewer-thumb.component';
@Component({
@@ -50,25 +53,25 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
private readonly element = inject(ElementRef);
private readonly document = inject(DOCUMENT);
@Input({ required: true }) pdfViewer: any;
@Input({ required: true }) pdfViewer: PDFViewer;
@Output()
close = new EventEmitter<void>();
virtualHeight: number = 0;
translateY: number = 0;
renderItems = [];
renderItems: PdfThumbnailPage[] = [];
width: number = 91;
currentHeight: number = 0;
private items = [];
private items: PdfThumbnailPage[] = [];
private readonly margin: number = 15;
private itemHeight: number = 114 + this.margin;
private previouslyFocusedElement: HTMLElement | null = null;
private keyManager: FocusKeyManager<PdfThumbComponent>;
@ContentChild(TemplateRef)
template: any;
template: TemplateRef<unknown>;
@ViewChildren(PdfThumbComponent)
thumbsList: QueryList<PdfThumbComponent>;
@@ -145,7 +148,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
}
}
trackByFn(_: number, item: any): number {
trackByFn(_: number, item: PdfThumbnailPage): number {
return item.id;
}
@@ -171,7 +174,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
}
}
getPages() {
getPages(): PdfThumbnailPage[] {
// eslint-disable-next-line no-underscore-dangle
return this.pdfViewer._pages.map((page) => ({
id: page.id,
@@ -181,12 +184,11 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
}));
}
private setHeight(id): number {
const height = this.pdfViewer.pdfDocument.getPage(id).then((page) => this.calculateHeight(page));
return height;
private setHeight(id: number): Promise<void> {
return this.pdfViewer.pdfDocument.getPage(id).then((page) => this.calculateHeight(page));
}
private calculateHeight(page) {
private calculateHeight(page: PDFPageProxy) {
const viewport = page.getViewport({ scale: 1 });
const pageRatio = viewport.width / viewport.height;
const height = Math.floor(this.width / pageRatio);
@@ -222,7 +224,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
};
}
private onPageChange(event) {
private onPageChange(event: PageChangingEvent) {
const index = this.renderItems.findIndex((element) => element.id === event.pageNumber);
if (index < 0) {

View File

@@ -30,7 +30,12 @@ import { PDFJS_MODULE, PDFJS_VIEWER_MODULE, PdfViewerComponent } from './pdf-vie
import pdfjsLibraryMock, { annotations } from '../mock/pdfjs-lib.mock';
import { TranslateService } from '@ngx-translate/core';
declare const pdfjsLib: any;
declare const pdfjsLib: {
PasswordResponses: {
NEED_PASSWORD: number;
INCORRECT_PASSWORD: number;
};
};
@Component({
selector: 'adf-url-test-component',
@@ -41,7 +46,7 @@ class UrlTestComponent {
@ViewChild(PdfViewerComponent, { static: true })
pdfViewerComponent: PdfViewerComponent;
urlFile: any;
urlFile: string;
constructor() {
this.urlFile = './fake-test-file.pdf';
@@ -57,7 +62,7 @@ class UrlTestPasswordComponent {
@ViewChild(PdfViewerComponent, { static: true })
pdfViewerComponent: PdfViewerComponent;
urlFile: any;
urlFile: string;
constructor() {
this.urlFile = './fake-test-password-file.pdf';
@@ -72,7 +77,7 @@ class BlobTestComponent {
@ViewChild(PdfViewerComponent, { static: true })
pdfViewerComponent: PdfViewerComponent;
blobFile: any;
blobFile: Blob;
constructor() {
this.blobFile = this.createFakeBlob();
@@ -101,7 +106,7 @@ class BlobTestComponent {
describe('Test PdfViewer component', () => {
let component: PdfViewerComponent;
let fixture: ComponentFixture<PdfViewerComponent>;
let change: any;
let change: SimpleChange;
let dialog: MatDialog;
let testingUtils: UnitTestingUtils;
@@ -265,17 +270,17 @@ describe('Test PdfViewer component', () => {
fixtureUrlTestPasswordComponent = TestBed.createComponent(UrlTestPasswordComponent);
componentUrlTestPasswordComponent = fixtureUrlTestPasswordComponent.componentInstance;
spyOn(dialog, 'open').and.callFake((_: any, context: any) => {
spyOn(dialog, 'open').and.callFake((_dialogComponent: unknown, context: { data: { reason: number } }) => {
if (context.data.reason === pdfjsLib.PasswordResponses.NEED_PASSWORD) {
return {
afterClosed: () => of('wrong_password')
} as any;
} as ReturnType<MatDialog['open']>;
}
if (context.data.reason === pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) {
return {
afterClosed: () => of('password')
} as any;
} as ReturnType<MatDialog['open']>;
}
return undefined;
@@ -328,7 +333,7 @@ describe('Test PdfViewer component', () => {
() =>
({
afterClosed: () => of('')
}) as any
}) as ReturnType<MatDialog['open']>
);
spyOn(componentUrlTestPasswordComponent.pdfViewerComponent.close, 'emit');
@@ -456,7 +461,9 @@ describe('Test PdfViewer - User interaction', () => {
component.urlFile = './fake-test-file.pdf';
fixture.detectChanges();
component.ngOnChanges({ urlFile: { currentValue: './fake-test-file.pdf' } } as any);
component.ngOnChanges({
urlFile: new SimpleChange(null, './fake-test-file.pdf', true)
});
flush();
}));
@@ -666,7 +673,10 @@ describe('Test PdfViewer - User interaction', () => {
it('should have corrected content in annotation popup', fakeAsync(() => {
dispatchAnnotationLayerRenderedEvent();
expect(getAnnotationTitle()).toBe('Annotation title');
expect(getAnnotationDate()).toBe('2/2/2026, 10:41:06 AM');
const dateText = getAnnotationDate();
// Date format may vary by locale, so check it contains the key parts
expect(dateText).toMatch(/2026/);
expect(dateText).toMatch(/10:41:06|10:41:6/);
expect(getAnnotationContent()).toBe('Annotation contents');
expect(getAnnotationPopupElement()).toBeDefined();
}));

View File

@@ -47,12 +47,41 @@ import { PdfPasswordDialogComponent } from '../pdf-viewer-password-dialog/pdf-vi
import { PdfThumbListComponent } from '../pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
import * as pdfjsLib from 'pdfjs-dist/build/pdf.min.mjs';
import { EventBus, PDFViewer } from 'pdfjs-dist/web/pdf_viewer.mjs';
import { OnProgressParameters, PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist/types/src/display/api';
import { OnProgressParameters, PDFDocumentLoadingTask, PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist/types/src/display/api';
import { IconModule } from '../../../icon/icon.module';
import { PDFDateString } from 'pdfjs-dist';
export type PdfScaleMode = 'init' | 'page-actual' | 'page-width' | 'page-height' | 'page-fit' | 'auto';
export interface PageChangingEvent {
pageNumber: number;
source?: {
container?: {
id?: string;
};
};
}
export interface PdfThumbnailPage {
id: number;
getWidth: () => number;
getHeight: () => number;
getPage: () => Promise<PDFPageProxy>;
}
export interface PdfAnnotationData {
titleObj?: {
str?: string;
};
modificationDate?: string;
}
export interface PdfAnnotationWithTitle extends PdfAnnotationData {
titleObj: {
str: string;
};
}
export const PDFJS_MODULE = new InjectionToken('PDFJS_MODULE', { factory: () => pdfjsLib });
export const PDFJS_VIEWER_MODULE = new InjectionToken('PDFJS_VIEWER_MODULE', { factory: () => PDFViewer });
@@ -93,19 +122,19 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
allowThumbnails = false;
@Input()
thumbnailsTemplate: TemplateRef<any> = null;
thumbnailsTemplate: TemplateRef<unknown> = null;
@Input()
cacheType: string = '';
@Output()
rendered = new EventEmitter<any>();
rendered = new EventEmitter<void>();
@Output()
error = new EventEmitter<any>();
error = new EventEmitter<void>();
@Output()
close = new EventEmitter<any>();
close = new EventEmitter<void>();
@Output()
pagesLoaded = new EventEmitter<void>();
@@ -127,7 +156,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
loadingTask: PDFDocumentLoadingTask;
isPanelDisabled = true;
showThumbnails: boolean = false;
pdfThumbnailsContext: { viewer: any } = { viewer: null };
pdfThumbnailsContext: { viewer: PDFViewer | null } = { viewer: null };
randomPdfId: string;
documentOverflow = false;
@@ -214,7 +243,12 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
const urlFile = changes['urlFile'];
if (urlFile?.currentValue) {
const pdfOptions: any = {
const pdfOptions: {
url: string;
withCredentials: boolean | undefined;
isEvalSupported: boolean;
httpHeaders?: { 'Cache-Control': string };
} & typeof this.pdfjsDefaultOptions = {
...this.pdfjsDefaultOptions,
url: urlFile.currentValue,
withCredentials: this.appConfigService.get<boolean>('auth.withCredentials', undefined),
@@ -233,7 +267,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
}
}
executePdf(pdfOptions: any) {
executePdf(pdfOptions: Parameters<typeof this.pdfjsLib.getDocument>[0]) {
this.setupPdfJsWorker().then(() => {
this.loadingTask = this.pdfjsLib.getDocument(pdfOptions);
@@ -282,7 +316,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
}
initPDFViewer(pdfDocument: PDFDocumentProxy) {
const viewer: any = this.getViewer();
const viewer: HTMLDivElement = this.getViewer();
const container = this.getDocumentContainer();
if (viewer && container) {
@@ -433,8 +467,8 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
return document.getElementById(`${this.randomPdfId}-viewer-pdf-viewer`) as HTMLDivElement;
}
private getViewer(): HTMLElement {
return document.getElementById(`${this.randomPdfId}-viewer-viewerPdf`);
private getViewer(): HTMLDivElement {
return document.getElementById(`${this.randomPdfId}-viewer-viewerPdf`) as HTMLDivElement;
}
checkPageFitInContainer(scale: number): number {
@@ -519,9 +553,9 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
* @param ticks number of ticks to zoom
*/
zoomIn(ticks?: number): void {
let newScale: any = this.pdfViewer.currentScaleValue;
let newScale: number = Number(this.pdfViewer.currentScaleValue);
do {
newScale = (newScale * this.DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Number((newScale * this.DEFAULT_SCALE_DELTA).toFixed(2));
newScale = Math.ceil(newScale * 10) / 10;
newScale = Math.min(this.MAX_SCALE, newScale);
} while (--ticks > 0 && newScale < this.MAX_SCALE);
@@ -535,9 +569,9 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
* @param ticks number of ticks to scale
*/
zoomOut(ticks?: number): void {
let newScale: any = this.pdfViewer.currentScaleValue;
let newScale: number = Number(this.pdfViewer.currentScaleValue);
do {
newScale = (newScale / this.DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Number((newScale / this.DEFAULT_SCALE_DELTA).toFixed(2));
newScale = Math.floor(newScale * 10) / 10;
newScale = Math.max(this.MIN_SCALE, newScale);
} while (--ticks > 0 && newScale > this.MIN_SCALE);
@@ -589,9 +623,13 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
/**
* Page Change Event
*
* @param event event
* @param event - page change event
* @param event.pageNumber - the new page number
* @param event.source - the source object
* @param event.source.container - the container element
* @param event.source.container.id - the container id
*/
onPageChange(event: any) {
onPageChange(event: PageChangingEvent) {
if (event.source && event.source.container.id === `${this.randomPdfId}-viewer-pdf-viewer`) {
this.page = event.pageNumber;
this.displayPage = event.pageNumber;
@@ -682,11 +720,11 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
}
}
private createAnnotationPopup(annotation: any, text: string, annotationElement: HTMLElement): void {
private createAnnotationPopup(annotation: PdfAnnotationData, text: string, annotationElement: HTMLElement): void {
const popupElement = document.createElement('div');
let headerElement: HTMLSpanElement;
if (annotation.titleObj?.str) {
headerElement = this.createAnnotationPopupHeader(annotation);
headerElement = this.createAnnotationPopupHeader(annotation as PdfAnnotationWithTitle);
}
const contentElement = this.createAnnotationPopupContent(text);
popupElement.classList.add('popup', 'adf-pdf-viewer-annotation-tooltip');
@@ -694,7 +732,7 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
annotationElement.appendChild(popupElement);
}
private createAnnotationPopupHeader(annotation: any): HTMLSpanElement {
private createAnnotationPopupHeader(annotation: PdfAnnotationWithTitle): HTMLSpanElement {
const headerElement = document.createElement('span');
const titleElement = document.createElement('span');
let dateElement: HTMLTimeElement;

View File

@@ -31,7 +31,7 @@ export class TxtViewerComponent implements OnChanges {
private readonly appConfigService = inject(AppConfigService);
@Input()
urlFile: any;
urlFile: string;
@Input()
blobFile: Blob;
@@ -86,7 +86,7 @@ export class TxtViewerComponent implements OnChanges {
this.content = reader.result;
};
reader.onerror = (error: any) => {
reader.onerror = (error: ProgressEvent<FileReader>) => {
reject(error);
};

View File

@@ -54,7 +54,7 @@ class DoubleViewerComponent {
viewer2: ViewerRenderComponent;
@ViewChild('viewerExtension', { static: true })
viewerTemplateExtensions: TemplateRef<any>;
viewerTemplateExtensions: TemplateRef<unknown>;
urlFileViewer1: string;
urlFileViewer2: string;

View File

@@ -89,7 +89,7 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
/** The template for the pdf thumbnails. */
@Input()
thumbnailsTemplate: TemplateRef<any> = null;
thumbnailsTemplate: TemplateRef<unknown> = null;
/** MIME type of the file content (when not determined by the filename extension). */
@Input()
@@ -124,7 +124,7 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
/** Template containing ViewerExtensionDirective instances providing different viewer extensions based on supported file extension. */
@Input()
viewerTemplateExtensions: TemplateRef<any>;
viewerTemplateExtensions: TemplateRef<unknown>;
/** Custom error message to be displayed in the viewer. */
@Input()
@@ -149,7 +149,7 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
@ViewChild(ImgViewerComponent)
imgViewer: ImgViewerComponent;
extensionTemplates: { template: TemplateRef<any>; isVisible: boolean }[] = [];
extensionTemplates: { template: TemplateRef<unknown>; isVisible: boolean }[] = [];
extensionsSupportedByTemplates: string[] = [];
extension: string;
internalFileName: string;

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, DebugElement, SimpleChanges } from '@angular/core';
import { Component, DebugElement, SimpleChange, SimpleChanges } from '@angular/core';
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { MatDialog } from '@angular/material/dialog';
import { of } from 'rxjs';
@@ -42,8 +42,8 @@ import { ThumbnailService } from '../../common/services/thumbnail.service';
class DummyDialogComponent {}
describe('ViewerComponent', () => {
let component: ViewerComponent<any>;
let fixture: ComponentFixture<ViewerComponent<any>>;
let component: ViewerComponent<unknown>;
let fixture: ComponentFixture<ViewerComponent<unknown>>;
let dialog: MatDialog;
let viewUtilService: ViewUtilService;
let appConfigService: AppConfigService;
@@ -106,7 +106,9 @@ describe('ViewerComponent', () => {
describe('Mime Type Test', () => {
it('should mimeType change when blobFile changes', () => {
const mockSimpleChanges: any = { blobFile: { currentValue: { type: 'image/png' } } };
const mockSimpleChanges: SimpleChanges = {
blobFile: new SimpleChange(null, { type: 'image/png' }, true)
};
component.ngOnChanges(mockSimpleChanges);
@@ -115,7 +117,10 @@ describe('ViewerComponent', () => {
it('should set mimeTypeIconUrl when mimeType changes and no nodeMimeType is provided', () => {
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue('image/png');
const mockSimpleChanges: any = { mimeType: { currentValue: 'image/png' }, nodeMimeType: undefined };
const mockSimpleChanges: SimpleChanges = {
mimeType: new SimpleChange(null, 'image/png', true),
nodeMimeType: undefined
};
component.ngOnChanges(mockSimpleChanges);
@@ -125,7 +130,10 @@ describe('ViewerComponent', () => {
it('should set mimeTypeIconUrl when nodeMimeType changes', () => {
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue('application/pdf');
const mockSimpleChanges: any = { mimeType: { currentValue: 'image/png' }, nodeMimeType: { currentValue: 'application/pdf' } };
const mockSimpleChanges: SimpleChanges = {
mimeType: new SimpleChange(null, 'image/png', true),
nodeMimeType: new SimpleChange(null, 'application/pdf', true)
};
component.ngOnChanges(mockSimpleChanges);
fixture.detectChanges();
@@ -523,7 +531,9 @@ describe('ViewerComponent', () => {
});
it('should file name be present if is overlay mode ', async () => {
const mockSimpleChanges: any = { blobFile: { currentValue: { type: 'image/png' } } };
const mockSimpleChanges: SimpleChanges = {
blobFile: new SimpleChange(null, { type: 'image/png' }, true)
};
component.ngOnChanges(mockSimpleChanges);
fixture.detectChanges();
await fixture.whenStable();
@@ -705,7 +715,7 @@ describe('ViewerComponent', () => {
downloadPromptReminderDelay: 2
}
};
dialogOpenSpy = spyOn(dialog, 'open').and.returnValue({ afterClosed: () => of(null) } as any);
dialogOpenSpy = spyOn(dialog, 'open').and.returnValue({ afterClosed: () => of(null) } as ReturnType<MatDialog['open']>);
component.urlFile = undefined;
component.clearDownloadPromptTimeouts();
});
@@ -716,11 +726,11 @@ describe('ViewerComponent', () => {
});
it('should configure reminder timeout to display non responsive dialog after initial dialog', fakeAsync(() => {
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.WAIT) } as any);
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.WAIT) } as ReturnType<MatDialog['open']>);
fixture.detectChanges();
tick(3000);
expect(component.downloadPromptReminderTimer).toBeDefined();
dialogOpenSpy.and.returnValue({ afterClosed: () => of(null) } as any);
dialogOpenSpy.and.returnValue({ afterClosed: () => of(null) } as ReturnType<MatDialog['open']>);
flush();
discardPeriodicTasks();
}));
@@ -741,12 +751,12 @@ describe('ViewerComponent', () => {
}));
it('should show reminder non responsive dialog after initial dialog', fakeAsync(() => {
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.WAIT) } as any);
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.WAIT) } as ReturnType<MatDialog['open']>);
fixture.detectChanges();
tick(3000);
expect(dialogOpenSpy).toHaveBeenCalled();
dialogOpenSpy.and.returnValue({ afterClosed: () => of(null) } as any);
dialogOpenSpy.and.returnValue({ afterClosed: () => of(null) } as ReturnType<MatDialog['open']>);
tick(2000);
expect(dialogOpenSpy).toHaveBeenCalledTimes(2);
@@ -755,7 +765,7 @@ describe('ViewerComponent', () => {
}));
it('should emit downloadFileEvent when DownloadPromptDialog return DownloadPromptActions.DOWNLOAD on close', fakeAsync(() => {
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.DOWNLOAD) } as any);
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.DOWNLOAD) } as ReturnType<MatDialog['open']>);
spyOn(component.downloadFile, 'emit');
fixture.detectChanges();
tick(3000);

View File

@@ -117,7 +117,7 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
mnuMoreActions: ViewerMoreActionsComponent;
@ContentChild('viewerExtensions', { static: false })
viewerTemplateExtensions: TemplateRef<any>;
viewerTemplateExtensions: TemplateRef<unknown>;
get CloseButtonPosition() {
return CloseButtonPosition;
@@ -190,11 +190,11 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
/** The template for the right sidebar. The template context contains the loaded node data. */
@Input()
sidebarRightTemplate: TemplateRef<any> = null;
sidebarRightTemplate: TemplateRef<unknown> = null;
/** The template for the left sidebar. The template context contains the loaded node data. */
@Input()
sidebarLeftTemplate: TemplateRef<any> = null;
sidebarLeftTemplate: TemplateRef<unknown> = null;
/** Enable when where is possible the editing functionalities */
@Input()
@@ -243,7 +243,7 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
/** Template containing ViewerExtensionDirective instances providing different viewer extensions based on supported file extension. */
@Input()
viewerExtensions: TemplateRef<any>;
viewerExtensions: TemplateRef<unknown>;
/** Identifier of a node that is opened by the viewer. */
@Input()

View File

@@ -17,7 +17,7 @@
import { Location } from '@angular/common';
import { SpyLocation } from '@angular/common/testing';
import { ChangeDetectorRef, ElementRef } from '@angular/core';
import { ChangeDetectorRef, ElementRef, TemplateRef } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ViewerRenderComponent } from '../components/viewer-render/viewer-render.component';
import { ViewerExtensionDirective } from './viewer-extension.directive';
@@ -50,7 +50,7 @@ describe('ExtensionViewerDirective', () => {
});
extensionViewerDirective = TestBed.inject(ViewerExtensionDirective);
viewerRenderer = TestBed.inject(ViewerRenderComponent);
extensionViewerDirective.templateModel = { template: '', isVisible: false };
extensionViewerDirective.templateModel = { template: {} as TemplateRef<unknown>, isVisible: false };
});
it('is defined', () => {

View File

@@ -26,7 +26,7 @@ export class ViewerExtensionDirective implements AfterContentInit {
private readonly viewerComponent = inject(ViewerRenderComponent);
@ContentChild(TemplateRef)
template: any;
template: TemplateRef<unknown>;
@Input()
urlFileContent: string;
@@ -37,7 +37,7 @@ export class ViewerExtensionDirective implements AfterContentInit {
@Input()
supportedExtensions: string[];
templateModel: any;
templateModel: { template: TemplateRef<unknown>; isVisible: boolean };
private readonly destroyRef = inject(DestroyRef);

View File

@@ -16,6 +16,29 @@
*/
import { Injectable } from '@angular/core';
import type { PDFViewer } from 'pdfjs-dist/types/web/pdf_viewer';
import type { PDFThumbnailViewer } from 'pdfjs-dist/types/web/pdf_thumbnail_viewer';
import type { PDFPageView } from 'pdfjs-dist/types/web/pdf_page_view';
interface VisiblePage {
id: number;
}
interface VisiblePages {
first?: VisiblePage;
last?: VisiblePage;
views?: Array<{ view: PDFPageView }>;
}
/**
* Type helper for accessing the resume method on PDFPageView.
* PDFPageView implements IRenderableView which includes a resume method,
* but the TypeScript definitions don't properly expose it.
*/
// cspell:ignore Renderable
interface ResumableView {
resume?: () => void;
}
/**
*
@@ -33,13 +56,13 @@ export class RenderingQueueServices {
CLEANUP_TIMEOUT: number = 30_000;
pdfViewer: any = null;
pdfThumbnailViewer: any = null;
onIdle: any = null;
pdfViewer: PDFViewer | null = null;
pdfThumbnailViewer: PDFThumbnailViewer | null = null;
onIdle: (() => void) | null = null;
highestPriorityPage: string | null = null;
idleTimeout: any = null;
printing: any = false;
idleTimeout: number | null = null;
printing = false;
isThumbnailViewEnabled = false;
/**
@@ -47,7 +70,7 @@ export class RenderingQueueServices {
*
* @param pdfViewer viewer instance
*/
setViewer(pdfViewer): void {
setViewer(pdfViewer: PDFViewer): void {
this.pdfViewer = pdfViewer;
}
@@ -56,7 +79,7 @@ export class RenderingQueueServices {
*
* @param pdfThumbnailViewer viewer instance
*/
setThumbnailViewer(pdfThumbnailViewer): void {
setThumbnailViewer(pdfThumbnailViewer: PDFThumbnailViewer): void {
this.pdfThumbnailViewer = pdfThumbnailViewer;
}
@@ -66,18 +89,18 @@ export class RenderingQueueServices {
* @param view view to render
* @returns `true` if the view has higher priority, otherwise `false`
*/
isHighestPriority(view: any): boolean {
isHighestPriority(view: PDFPageView): boolean {
return this.highestPriorityPage === view.renderingId;
}
renderHighestPriority(currentlyVisiblePages) {
renderHighestPriority(currentlyVisiblePages?: unknown): void {
if (this.idleTimeout) {
clearTimeout(this.idleTimeout);
this.idleTimeout = null;
}
// Pages have a higher priority than thumbnails, so check them first.
if (this.pdfViewer.forceRendering(currentlyVisiblePages)) {
if (this.pdfViewer?.forceRendering(currentlyVisiblePages)) {
return;
}
// No pages needed rendering so check thumbnails.
@@ -91,11 +114,23 @@ export class RenderingQueueServices {
}
if (this.onIdle) {
this.idleTimeout = setTimeout(this.onIdle.bind(this), this.CLEANUP_TIMEOUT);
// Type assertion needed: setTimeout returns NodeJS.Timeout in Node types,
// but returns number at runtime in browser (where this code executes).
// PDFRenderingQueue interface requires idleTimeout to be number.
this.idleTimeout = setTimeout(this.onIdle.bind(this), this.CLEANUP_TIMEOUT) as unknown as number;
}
}
getHighestPriority(visible, views, scrolledDown) {
/**
* Gets the highest priority page to render from the visible pages
* This method is part of the PDFRenderingQueue interface compatibility
*
* @param visible visible pages information
* @param views array of page views
* @param scrolledDown whether the user scrolled down
* @returns the highest priority page view to render, null if all done, or false if no visible pages
*/
getHighestPriority(visible: VisiblePages, views: PDFPageView[], scrolledDown: boolean): PDFPageView | null | false {
// The state has changed figure out which page has the highest priority to
// render next (if any).
// Priority:
@@ -104,6 +139,10 @@ export class RenderingQueueServices {
// 2 if last scrolled up page before the visible pages
const visibleViews = visible.views;
if (!visibleViews) {
return false;
}
const numberVisible = visibleViews.length;
if (numberVisible === 0) {
return false;
@@ -116,13 +155,13 @@ export class RenderingQueueServices {
}
// All the visible views have rendered, try to render next/previous pages.
if (scrolledDown) {
if (scrolledDown && visible.last) {
const nextPageIndex = visible.last.id;
// ID's start at 1 so no need to add 1.
if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) {
return views[nextPageIndex];
}
} else {
} else if (visible.first) {
const previousPageIndex = visible.first.id - 2;
if (views[previousPageIndex] && !this.isViewFinished(views[previousPageIndex])) {
return views[previousPageIndex];
@@ -142,7 +181,7 @@ export class RenderingQueueServices {
* @param view the View instance to check
* @returns `true` if rendering is finished, otherwise `false`
*/
isViewFinished(view): boolean {
isViewFinished(view: PDFPageView): boolean {
return view.renderingState === this.renderingStates.FINISHED;
}
@@ -154,7 +193,7 @@ export class RenderingQueueServices {
* @param view View instance to render
* @returns the rendered state of the view
*/
renderView(view: any): boolean {
renderView(view: PDFPageView): boolean {
const state = view.renderingState;
switch (state) {
case this.renderingStates.FINISHED: {
@@ -162,7 +201,10 @@ export class RenderingQueueServices {
}
case this.renderingStates.PAUSED: {
this.highestPriorityPage = view.renderingId;
view.resume();
const resumableView = view as unknown as ResumableView;
if (resumableView.resume) {
resumableView.resume();
}
break;
}
case this.renderingStates.RUNNING: {
@@ -171,10 +213,9 @@ export class RenderingQueueServices {
}
case this.renderingStates.INITIAL: {
this.highestPriorityPage = view.renderingId;
// eslint-disable-next-line space-before-function-paren
const continueRendering = function () {
const continueRendering = () => {
this.renderHighestPriority();
}.bind(this);
};
view.draw().then(continueRendering, continueRendering);
break;
}

View File

@@ -26,4 +26,4 @@ TestBed.initTestEnvironment(GlobalTestingModule, platformBrowserDynamicTesting()
teardown: { destroyAfterEach: true }
});
(window as any).pdfjsLib = pdfjsLibraryMock;
(window as unknown as { pdfjsLib: typeof pdfjsLibraryMock }).pdfjsLib = pdfjsLibraryMock;

View File

@@ -7,6 +7,10 @@ const { constants } = require('karma');
module.exports = function (config) {
config.set({
basePath: '',
files: [
{ pattern: '../../node_modules/pdfjs-dist/build/pdf.min.mjs', type: 'module', included: true, watched: false },
{ pattern: '../../node_modules/pdfjs-dist/build/pdf.worker.min.mjs', type: 'module', included: true, watched: false }
],
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),

View File

@@ -9,6 +9,8 @@ module.exports = function (config) {
basePath: '../../',
files: [
{ pattern: 'node_modules/pdfjs-dist/build/pdf.min.mjs', type: 'module', included: true, watched: false },
{ pattern: 'node_modules/pdfjs-dist/build/pdf.worker.min.mjs', type: 'module', included: true, watched: false },
{ pattern: 'node_modules/chart.js/dist/Chart.js', included: true, watched: false },
{ pattern: 'node_modules/raphael/raphael.min.js', included: true, watched: false },
{

View File

@@ -17,6 +17,17 @@
import { BaseApi } from './base.api';
/**
* Product version model for Process Services.
*/
export interface BpmProductVersionModel {
edition: string;
majorVersion: string;
revisionVersion: string;
minorVersion: string;
type: string;
}
/**
* About service.
*/
@@ -26,7 +37,7 @@ export class AboutApi extends BaseApi {
* Provides information about the running Alfresco Process Services Suite. The response payload object has the properties type, majorVersion, minorVersion, revisionVersion and edition.
* @return Promise<{ [key: string]: string; }>
*/
getAppVersion(): Promise<{ [key: string]: string }> {
getAppVersion(): Promise<BpmProductVersionModel> {
return this.get({
path: '/api/enterprise/app-version'
});

View File

@@ -8,6 +8,8 @@ module.exports = function (config) {
config.set({
basePath: '../../',
files: [
{ pattern: 'node_modules/pdfjs-dist/build/pdf.min.mjs', type: 'module', included: true, watched: false },
{ pattern: 'node_modules/pdfjs-dist/build/pdf.worker.min.mjs', type: 'module', included: true, watched: false },
{
pattern: 'node_modules/@angular/material/prebuilt-themes/indigo-pink.css',
included: true,

View File

@@ -8,6 +8,8 @@ module.exports = function (config) {
config.set({
basePath: '../../',
files: [
{ pattern: 'node_modules/pdfjs-dist/build/pdf.min.mjs', type: 'module', included: true, watched: false },
{ pattern: 'node_modules/pdfjs-dist/build/pdf.worker.min.mjs', type: 'module', included: true, watched: false },
{
pattern: 'node_modules/@angular/material/prebuilt-themes/indigo-pink.css',
included: true,