Pull request #285: RED-2135

Merge in RED/ui from RED-2135 to master

* commit 'f98dd785b6662f4b50590ae789911ecda525d41e':
  update config and docker entrypoint
  update config service, remove app bootstrapped & config module
  move server error interceptor, update app config service
  update pdfviewer utils
  update other packages and pdftron
  update some packages
  update angular cdk and baseHref
  nx updates
This commit is contained in:
Dan Percic 2021-09-21 09:45:26 +02:00 committed by Timo Bejan
commit af92ca7148
49 changed files with 3263 additions and 2894 deletions

2
.gitignore vendored
View File

@ -41,3 +41,5 @@ Thumbs.db
version.properties
paligo-styles/style.css*
migrations.json

View File

@ -19,6 +19,57 @@
"@nrwl/angular:component": {}
},
"projects": {
"common-ui": {
"projectType": "library",
"root": "libs/common-ui",
"sourceRoot": "libs/common-ui/src",
"prefix": "redaction",
"architect": {
"test": {
"builder": "@nrwl/jest:jest",
"outputs": ["coverage/libs/common-ui"],
"options": {
"jestConfig": "libs/common-ui/jest.config.js",
"passWithNoTests": true
}
},
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["libs/common-ui/src/**/*.ts", "libs/common-ui/src/**/*.html"]
},
"outputs": ["{options.outputFile}"]
}
}
},
"red-cache": {
"projectType": "library",
"root": "libs/red-cache",
"sourceRoot": "libs/red-cache/src",
"prefix": "redaction",
"architect": {
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["libs/red-cache/src/**/*.ts", "libs/red-cache/src/**/*.html"]
},
"outputs": ["{options.outputFile}"]
},
"test": {
"builder": "@nrwl/jest:jest",
"options": {
"jestConfig": "libs/red-cache/jest.config.js",
"passWithNoTests": true
},
"outputs": ["coverage/libs/red-cache"]
}
},
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
}
},
"red-ui": {
"projectType": "application",
"schematics": {
@ -38,6 +89,7 @@
"main": "apps/red-ui/src/main.ts",
"polyfills": "apps/red-ui/src/polyfills.ts",
"tsConfig": "apps/red-ui/tsconfig.app.json",
"baseHref": "/ui/",
"assets": [
"apps/red-ui/src/favicon.ico",
{
@ -58,6 +110,9 @@
"apps/red-ui/src/manifest.webmanifest"
],
"styles": ["apps/red-ui/src/styles.scss", "libs/common-ui/src/assets/styles/common.scss"],
"stylePreprocessorOptions": {
"includePaths": ["./apps/red-ui/src/assets/styles"]
},
"scripts": ["node_modules/@pdftron/webviewer/webviewer.min.js"],
"vendorChunk": true,
"extractLicenses": false,
@ -120,7 +175,8 @@
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["apps/red-ui/src/**/*.ts", "apps/red-ui/src/**/*.html"]
}
},
"outputs": ["{options.outputFile}"]
},
"test": {
"builder": "@nrwl/jest:jest",
@ -149,7 +205,8 @@
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["libs/red-ui-http/src/**/*.ts", "libs/red-ui-http/src/**/*.html"]
}
},
"outputs": ["{options.outputFile}"]
},
"test": {
"builder": "@nrwl/jest:jest",
@ -165,55 +222,6 @@
"style": "scss"
}
}
},
"red-cache": {
"projectType": "library",
"root": "libs/red-cache",
"sourceRoot": "libs/red-cache/src",
"prefix": "redaction",
"architect": {
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["libs/red-cache/src/**/*.ts", "libs/red-cache/src/**/*.html"]
}
},
"test": {
"builder": "@nrwl/jest:jest",
"options": {
"jestConfig": "libs/red-cache/jest.config.js",
"passWithNoTests": true
},
"outputs": ["coverage/libs/red-cache"]
}
},
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
}
},
"common-ui": {
"projectType": "library",
"root": "libs/common-ui",
"sourceRoot": "libs/common-ui/src",
"prefix": "redaction",
"architect": {
"test": {
"builder": "@nrwl/jest:jest",
"outputs": ["coverage/libs/common-ui"],
"options": {
"jestConfig": "libs/common-ui/jest.config.js",
"passWithNoTests": true
}
},
"lint": {
"builder": "@nrwl/linter:eslint",
"options": {
"lintFilePatterns": ["libs/common-ui/src/**/*.ts", "libs/common-ui/src/**/*.html"]
}
}
}
}
}
}

View File

@ -4,9 +4,7 @@ module.exports = {
globals: {
'ts-jest': {
stringifyContentPathRegex: '\\.(html|svg)$',
astTransformers: {
before: ['jest-preset-angular/build/InlineFilesTransformer', 'jest-preset-angular/build/StripStylesTransformer']
},
tsconfig: '<rootDir>/tsconfig.spec.json'
}
},
@ -17,5 +15,6 @@ module.exports = {
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment'
]
],
transform: { '^.+\\.(ts|js|html)$': 'jest-preset-angular' }
};

View File

@ -30,16 +30,16 @@ import { MONACO_PATH, MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
import { GlobalErrorHandler } from '@utils/global-error-handler.service';
import { REDMissingTranslationHandler } from '@utils/missing-translations-handler';
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
import { configurationInitializer } from '@app-config/configuration.initializer';
import { AppConfigService } from '@app-config/app-config.service';
import { configurationInitializer } from '@utils/configuration.initializer';
import { ConfigService } from '@services/config.service';
import { SpotlightSearchComponent } from '@components/spotlight-search/spotlight-search.component';
import { PruningTranslationLoader } from '@utils/pruning-translation-loader';
import { DatePipe } from '@shared/pipes/date.pipe';
import * as links from '../assets/help-mode/links.json';
import { HELP_DOCS, IqserHelpModeModule } from '@iqser/common-ui';
import { ServerErrorInterceptor } from '@utils/server-error-interceptor';
import { HELP_DOCS, IqserHelpModeModule, MAX_RETRIES_ON_SERVER_ERROR, ServerErrorInterceptor } from '@iqser/common-ui';
import { KeycloakService } from 'keycloak-angular';
export function httpLoaderFactory(httpClient: HttpClient) {
export function httpLoaderFactory(httpClient: HttpClient): PruningTranslationLoader {
return new PruningTranslationLoader(httpClient, '/assets/i18n/', '.json');
}
@ -131,7 +131,7 @@ const components = [
provide: APP_INITIALIZER,
multi: true,
useFactory: configurationInitializer,
deps: [Title, AppConfigService, GeneralSettingsControllerService]
deps: [KeycloakService, Title, ConfigService, GeneralSettingsControllerService]
},
{
provide: MONACO_PATH,
@ -145,6 +145,11 @@ const components = [
provide: HELP_DOCS,
useValue: links
},
{
provide: MAX_RETRIES_ON_SERVER_ERROR,
useFactory: (configService: ConfigService) => configService.values.MAX_RETRIES_ON_SERVER_ERROR,
deps: [ConfigService]
},
DatePipe
],
bootstrap: [AppComponent]

View File

@ -1,19 +1,19 @@
<section>
<p *ngIf="!configuredAdminName && !configuredAdminUrl" class="heading-xl" translate="auth-error.heading"></p>
<p *ngIf="!adminName && !adminUrl" class="heading-xl" translate="auth-error.heading"></p>
<p
*ngIf="configuredAdminName && configuredAdminUrl"
[innerHTML]="'auth-error.heading-with-name-and-link' | translate: { adminName: configuredAdminName, adminUrl: configuredAdminUrl }"
*ngIf="adminName && adminUrl"
[innerHTML]="'auth-error.heading-with-name-and-link' | translate: { adminName: adminName, adminUrl: adminUrl }"
class="heading-xl"
></p>
<p
*ngIf="configuredAdminName && !configuredAdminUrl"
[innerHTML]="'auth-error.heading-with-name' | translate: { adminName: configuredAdminName }"
*ngIf="adminName && !adminUrl"
[innerHTML]="'auth-error.heading-with-name' | translate: { adminName: adminName }"
class="heading-xl"
></p>
<p
*ngIf="!configuredAdminName && configuredAdminUrl"
[innerHTML]="'auth-error.heading-with-link' | translate: { adminName: configuredAdminName }"
*ngIf="!adminName && adminUrl"
[innerHTML]="'auth-error.heading-with-link' | translate: { adminName: adminName }"
class="heading-xl"
></p>
<a (click)="logout()" translate="auth-error.logout"></a>
<a (click)="userService.logout()" translate="auth-error.logout"></a>
</section>

View File

@ -1,24 +1,15 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { UserService } from '@services/user.service';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
@Component({
selector: 'redaction-auth-error',
templateUrl: './auth-error.component.html',
styleUrls: ['./auth-error.component.scss']
})
export class AuthErrorComponent implements OnInit {
configuredAdminName: string;
configuredAdminUrl: string;
export class AuthErrorComponent {
adminName = this._configService.values.ADMIN_CONTACT_NAME;
adminUrl = this._configService.values.ADMIN_CONTACT_URL;
constructor(private readonly _userService: UserService, private readonly _appConfigService: AppConfigService) {}
ngOnInit(): void {
this.configuredAdminName = this._appConfigService.getConfig(AppConfigKey.ADMIN_CONTACT_NAME);
this.configuredAdminUrl = this._appConfigService.getConfig(AppConfigKey.ADMIN_CONTACT_URL);
}
logout() {
this._userService.logout();
}
constructor(readonly userService: UserService, private readonly _configService: ConfigService) {}
}

View File

@ -5,7 +5,7 @@ import { PermissionsService } from '@services/permissions.service';
import { LanguageService } from '@i18n/language.service';
import { TranslateService } from '@ngx-translate/core';
import { UserControllerService } from '@redaction/red-ui-http';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { DomSanitizer } from '@angular/platform-browser';
import { languagesTranslations } from '../../translations/languages-translations';
import { LoadingService } from '@iqser/common-ui';
@ -26,7 +26,7 @@ export class UserProfileScreenComponent implements OnInit {
readonly permissionsService: PermissionsService,
private readonly _formBuilder: FormBuilder,
private readonly _userService: UserService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _userControllerService: UserControllerService,
private readonly _languageService: LanguageService,
private readonly _domSanitizer: DomSanitizer,
@ -42,7 +42,7 @@ export class UserProfileScreenComponent implements OnInit {
});
this.changePasswordUrl = this._domSanitizer.bypassSecurityTrustResourceUrl(
this._appConfigService.getConfig(AppConfigKey.OAUTH_URL) + '/account/password'
this._configService.values.OAUTH_URL + '/account/password'
);
}

View File

@ -7,7 +7,7 @@ import {
SmtpConfigurationControllerService,
SMTPConfigurationModel
} from '@redaction/red-ui-http';
import { AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { AutoUnsubscribe, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { UserService } from '@services/user.service';
@ -33,7 +33,7 @@ export class GeneralConfigScreenComponent extends AutoUnsubscribe implements OnI
private readonly _formBuilder: FormBuilder,
private readonly _loadingService: LoadingService,
private readonly _dialogService: AdminDialogService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _smtpConfigService: SmtpConfigurationControllerService,
private readonly _generalSettingsControllerService: GeneralSettingsControllerService
) {
@ -112,7 +112,7 @@ export class GeneralConfigScreenComponent extends AutoUnsubscribe implements OnI
await this._generalSettingsControllerService.updateGeneralConfigurations(configFormValues).toPromise();
this._initialGeneralConfiguration = await this._generalSettingsControllerService.getGeneralConfigurations().toPromise();
this._appConfigService.updateDisplayName(this._initialGeneralConfiguration.displayName);
this._configService.updateDisplayName(this._initialGeneralConfiguration.displayName);
this._loadingService.stop();
}

View File

@ -16,17 +16,17 @@
<div class="grid-container">
<div class="row">
<div translate="license-info-screen.backend-version"></div>
<div>{{ appConfigService.getConfig('BACKEND_APP_VERSION', '-') }}</div>
<div>{{ configService.values.BACKEND_APP_VERSION || '-' }}</div>
</div>
<div class="row">
<div translate="license-info-screen.frontend-version"></div>
<div>{{ appConfigService.getConfig('FRONTEND_APP_VERSION', '-') }}</div>
<div>{{ configService.values.FRONTEND_APP_VERSION || '-' }}</div>
</div>
<div class="row">
<div translate="license-info-screen.custom-app-title"></div>
<div>{{ appConfigService.getConfig('APP_NAME', '-') }}</div>
<div>{{ configService.values.APP_NAME || '-' }}</div>
</div>
<div class="row">
@ -45,14 +45,14 @@
<div class="row">
<div translate="license-info-screen.licensed-to"></div>
<div>{{ appConfigService.getConfig('LICENSE_CUSTOMER', '-') }}</div>
<div>{{ configService.values.LICENSE_CUSTOMER || '-' }}</div>
</div>
<div class="row">
<div translate="license-info-screen.licensing-period"></div>
<div>
{{ appConfigService.getConfig('LICENSE_START', '-') }} /
{{ appConfigService.getConfig('LICENSE_END', '-') }}
{{ configService.values.LICENSE_START || '-' }} /
{{ configService.values.LICENSE_END || '-' }}
</div>
</div>
@ -107,8 +107,7 @@
[yAxisLabelRight]="'license-info-screen.chart.total-pages' | translate"
[yAxisLabel]="'license-info-screen.chart.pages-per-month' | translate"
[yAxis]="true"
>
</combo-chart-component>
></combo-chart-component>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { LicenseReport, LicenseReportControllerService } from '@redaction/red-ui-http';
import { AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import * as moment from 'moment';
import { TranslateService } from '@ngx-translate/core';
import { IconButtonTypes, LoadingService } from '@iqser/common-ui';
@ -45,8 +45,8 @@ export class LicenseInformationScreenComponent implements OnInit {
};
constructor(
readonly configService: ConfigService,
private readonly _userService: UserService,
readonly appConfigService: AppConfigService,
private readonly _loadingService: LoadingService,
readonly routerHistoryService: RouterHistoryService,
private readonly _translateService: TranslateService,
@ -60,9 +60,9 @@ export class LicenseInformationScreenComponent implements OnInit {
}
async ngOnInit() {
this.totalLicensedNumberOfPages = this.appConfigService.getConfig('LICENSE_PAGE_COUNT', 0);
const startDate = moment(this.appConfigService.getConfig('LICENSE_START'), 'DD-MM-YYYY');
const endDate = moment(this.appConfigService.getConfig('LICENSE_END'), 'DD-MM-YYYY');
this.totalLicensedNumberOfPages = this.configService.values.LICENSE_PAGE_COUNT || 0;
const startDate = moment(this.configService.values.LICENSE_START, 'DD-MM-YYYY');
const endDate = moment(this.configService.values.LICENSE_END, 'DD-MM-YYYY');
await this._setMonthlyStats(startDate, endDate);
@ -93,7 +93,7 @@ export class LicenseInformationScreenComponent implements OnInit {
}
sendMail(): void {
const licenseCustomer = this.appConfigService.getConfig('LICENSE_CUSTOMER');
const licenseCustomer = this.configService.values.LICENSE_CUSTOMER;
const subject = this._translateService.instant('license-info-screen.email.title', {
licenseCustomer
});
@ -106,7 +106,7 @@ export class LicenseInformationScreenComponent implements OnInit {
pages: this.totalLicensedNumberOfPages
})
].join(lineBreak);
window.location.href = `mailto:${this.appConfigService.getConfig('LICENSE_EMAIL')}?subject=${subject}&body=${body}`;
window.location.href = `mailto:${this.configService.values.LICENSE_EMAIL}?subject=${subject}&body=${body}`;
}
private async _setMonthlyStats(startDate: moment.Moment, endDate: moment.Moment) {

View File

@ -9,7 +9,7 @@ import {
SortingOrders,
TableColumnConfig
} from '@iqser/common-ui';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import * as moment from 'moment';
import { DossiersService } from '../../../dossier/services/dossiers.service';
import { AdminDialogService } from '../../services/admin-dialog.service';
@ -45,14 +45,14 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
@ViewChild('deletedTimeTemplate', { static: true }) deletedTimeTemplate: TemplateRef<never>;
@ViewChild('restoreDateTemplate', { static: true }) restoreDateTemplate: TemplateRef<never>;
protected readonly _primaryKey = 'dossierName';
private readonly _deleteRetentionHours = this._appConfigService.getConfig(AppConfigKey.DELETE_RETENTION_HOURS);
private readonly _deleteRetentionHours = this._configService.values.DELETE_RETENTION_HOURS;
constructor(
protected readonly _injector: Injector,
private readonly _loadingService: LoadingService,
private readonly _dossiersService: DossiersService,
readonly routerHistoryService: RouterHistoryService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _adminDialogService: AdminDialogService
) {
super(_injector);

View File

@ -5,9 +5,8 @@ import { AppStateService } from '@state/app-state.service';
import { environment } from '@environments/environment';
import { HttpClient } from '@angular/common/http';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Debounce, IconButtonTypes, LoadingService } from '@iqser/common-ui';
import { Debounce, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { WatermarkControllerService, WatermarkModelRes } from '@redaction/red-ui-http';
import { Toaster } from '@iqser/common-ui';
import { ActivatedRoute } from '@angular/router';
import { BASE_HREF } from '../../../../tokens';
import { stampPDFPage } from '@utils/page-stamper';
@ -137,7 +136,7 @@ export class WatermarkScreenComponent implements OnInit {
).then(instance => {
this._instance = instance;
instance.docViewer.on('documentLoaded', async () => {
instance.Core.documentViewer.on('documentLoaded', async () => {
this._loadingService.stop();
await this._drawWatermark();
});
@ -149,19 +148,19 @@ export class WatermarkScreenComponent implements OnInit {
responseType: 'blob'
})
.subscribe(blobData => {
this._instance.loadDocument(blobData, { filename: 'blank.pdf' });
this._instance.UI.loadDocument(blobData, { filename: 'blank.pdf' });
});
});
}
}
private _disableElements() {
this._instance.disableElements(['header', 'toolsHeader', 'pageNavOverlay', 'textPopup']);
this._instance.UI.disableElements(['header', 'toolsHeader', 'pageNavOverlay', 'textPopup']);
}
private async _drawWatermark() {
const pdfNet = this._instance.PDFNet;
const document = await this._instance.docViewer.getDocument().getPDFDoc();
const pdfNet = this._instance.Core.PDFNet;
const document = await this._instance.Core.documentViewer.getDocument().getPDFDoc();
const text = this.configForm.get('text').value || '';
const fontSize = this.configForm.get('fontSize').value;
@ -171,8 +170,8 @@ export class WatermarkScreenComponent implements OnInit {
const color = this.configForm.get('hexColor').value;
await stampPDFPage(document, pdfNet, text, fontSize, fontType, orientation, opacity, color, [1]);
this._instance.docViewer.refreshAll();
this._instance.docViewer.updateView([0], 0);
this._instance.Core.documentViewer.refreshAll();
this._instance.Core.documentViewer.updateView([0], 0);
this._changeDetectorRef.detectChanges();
}

View File

@ -1,11 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { AppConfigService } from './app-config.service';
@NgModule({
declarations: [],
imports: [CommonModule, HttpClientModule],
providers: [AppConfigService]
})
export class AppConfigModule {}

View File

@ -1,83 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { tap } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { Title } from '@angular/platform-browser';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import packageInfo from '../../../../../../package.json';
import { CacheApiService, wipeCaches } from '@redaction/red-cache';
export enum AppConfigKey {
OAUTH_URL = 'OAUTH_URL',
OAUTH_CLIENT_ID = 'OAUTH_CLIENT_ID',
OAUTH_IDP_HINT = 'OAUTH_IDP_HINT',
API_URL = 'API_URL',
ADMIN_CONTACT_NAME = 'ADMIN_CONTACT_NAME',
ADMIN_CONTACT_URL = 'ADMIN_CONTACT_URL',
AUTO_READ_TIME = 'AUTO_READ_TIME',
SELECTION_MODE = 'SELECTION_MODE',
MAX_FILE_SIZE_MB = 'MAX_FILE_SIZE_MB',
RECENT_PERIOD_IN_HOURS = 'RECENT_PERIOD_IN_HOURS',
DELETE_RETENTION_HOURS = 'DELETE_RETENTION_HOURS',
APP_NAME = 'APP_NAME',
// TODO
BACKEND_APP_VERSION = 'BACKEND_APP_VERSION',
FRONTEND_APP_VERSION = 'FRONTEND_APP_VERSION',
EULA_URL = 'EULA_URL',
LICENSE_CUSTOMER = 'LICENSE_CUSTOMER',
LICENSE_EMAIL = 'LICENSE_EMAIL',
LICENSE_START = 'LICENSE_START',
LICENSE_END = 'LICENSE_END',
LICENSE_PAGE_COUNT = 'LICENSE_PAGE_COUNT'
}
@Injectable({
providedIn: 'root'
})
export class AppConfigService {
private _config: { [key in AppConfigKey]?: any } = {};
constructor(
private readonly _httpClient: HttpClient,
private readonly _cacheApiService: CacheApiService,
private readonly _titleService: Title
) {}
get version(): string {
return packageInfo.version;
}
loadAppConfig(): Observable<any> {
this._cacheApiService.getCachedValue(AppConfigKey.FRONTEND_APP_VERSION).then(async lastVersion => {
console.log('[REDACTION] Last app version: ', lastVersion, ' current version ', this.version);
if (lastVersion !== this.version) {
console.log('[REDACTION] Version-missmatch - wiping caches!');
await wipeCaches();
}
await this._cacheApiService.cacheValue(AppConfigKey.FRONTEND_APP_VERSION, this.version);
});
return this._httpClient.get<any>('/assets/config/config.json').pipe(
tap(config => {
console.log('[REDACTION] Started with config: ', config);
this._config = config;
this._config[AppConfigKey.FRONTEND_APP_VERSION] = this.version;
})
);
}
updateDisplayName(name: string) {
this.setConfig(AppConfigKey.APP_NAME, name);
this._titleService.setTitle(this.getConfig(AppConfigKey.APP_NAME, 'RedactManager'));
}
setConfig(key: AppConfigKey, value: any) {
this._config[key] = value;
}
getConfig(key: AppConfigKey | string, defaultValue?: any) {
return this._config[key] ? this._config[key] : defaultValue;
}
}

View File

@ -1,28 +0,0 @@
import { GeneralSettingsControllerService } from '@redaction/red-ui-http';
import { catchError, mergeMap, take, tap } from 'rxjs/operators';
import { AppConfigService } from './app-config.service';
import { Title } from '@angular/platform-browser';
import { APP_BOOTSTRAPPED } from '../bootstrap/app-bootstrap';
import { of } from 'rxjs';
export function configurationInitializer(
title: Title,
appConfigService: AppConfigService,
generalSettingsControllerService: GeneralSettingsControllerService
) {
return () =>
APP_BOOTSTRAPPED.pipe(
mergeMap(() =>
generalSettingsControllerService.getGeneralConfigurations().pipe(
tap(configuration => {
appConfigService.updateDisplayName(configuration.displayName);
})
)
),
catchError(() => {
title.setTitle('RedactManager');
return of({});
}),
take(1)
).toPromise();
}

View File

@ -2,7 +2,7 @@ import { Inject, Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';
import { UserService } from '@services/user.service';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { BASE_HREF } from '../../tokens';
@Injectable({
@ -13,16 +13,16 @@ export class AuthGuard extends KeycloakAuthGuard {
@Inject(BASE_HREF) private readonly _baseHref: string,
protected readonly _router: Router,
protected readonly _keycloak: KeycloakService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _userService: UserService
) {
super(_router, _keycloak);
}
async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
if (!this.authenticated) {
await this._keycloak.login({
idpHint: this._appConfigService.getConfig(AppConfigKey.OAUTH_IDP_HINT, null),
idpHint: this._configService.values.OAUTH_IDP_HINT,
redirectUri: window.location.origin + this._baseHref + state.url
});
return false;

View File

@ -1,59 +1,47 @@
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { AppConfigModule } from '@app-config/app-config.module';
import { KeycloakAngularModule, KeycloakOptions, KeycloakService } from 'keycloak-angular';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { BASE_HREF } from '../../tokens';
import { APP_BOOTSTRAPPED } from '../bootstrap/app-bootstrap';
export function keycloakInitializer(keycloak: KeycloakService, appConfigService: AppConfigService, baseUrl) {
return () =>
appConfigService
.loadAppConfig()
.toPromise()
.then(() => {
let url = appConfigService.getConfig(AppConfigKey.OAUTH_URL);
url = url.replace(/\/$/, ''); // remove trailing slash
const realm = url.substring(url.lastIndexOf('/') + 1, url.length);
url = url.substr(0, url.lastIndexOf('/realms'));
const options: KeycloakOptions = {
config: {
url: url,
realm: realm,
clientId: appConfigService.getConfig(AppConfigKey.OAUTH_CLIENT_ID)
},
initOptions: {
checkLoginIframe: false,
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + baseUrl + '/assets/oauth/silent-refresh.html',
flow: 'standard'
},
enableBearerInterceptor: true
};
return keycloak
.init(options)
.then(() => configureAutomaticRedirectToLoginScreen(keycloak))
.then(() => APP_BOOTSTRAPPED.next(true));
});
export function keycloakInitializer(keycloakService: KeycloakService, configService: ConfigService, baseUrl: string): () => Promise<void> {
let url = configService.values.OAUTH_URL;
url = url.replace(/\/$/, ''); // remove trailing slash
const realm = url.substring(url.lastIndexOf('/') + 1, url.length);
url = url.substr(0, url.lastIndexOf('/realms'));
const options: KeycloakOptions = {
config: {
url: url,
realm: realm,
clientId: configService.values.OAUTH_CLIENT_ID
},
initOptions: {
checkLoginIframe: false,
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + baseUrl + '/assets/oauth/silent-refresh.html',
flow: 'standard'
},
enableBearerInterceptor: true
};
return () => keycloakService.init(options).then(() => configureAutomaticRedirectToLoginScreen(keycloakService));
}
function configureAutomaticRedirectToLoginScreen(keyCloakService: KeycloakService) {
keyCloakService.getKeycloakInstance().onAuthRefreshError = () => {
keyCloakService.logout();
keyCloakService.getKeycloakInstance().onAuthRefreshError = async () => {
await keyCloakService.logout();
};
}
@NgModule({
declarations: [],
imports: [CommonModule, HttpClientModule, KeycloakAngularModule, AppConfigModule],
imports: [CommonModule, HttpClientModule, KeycloakAngularModule],
providers: [
{
provide: APP_INITIALIZER,
useFactory: keycloakInitializer,
multi: true,
deps: [KeycloakService, AppConfigService, BASE_HREF]
deps: [KeycloakService, ConfigService, BASE_HREF]
}
]
})

View File

@ -1,3 +0,0 @@
import { ReplaySubject } from 'rxjs';
export const APP_BOOTSTRAPPED = new ReplaySubject<boolean>();

View File

@ -48,8 +48,8 @@ export class AnnotationActionsComponent implements OnInit {
}
get viewerAnnotations() {
if (this.viewer?.annotManager) {
return this._annotations.map(a => this.viewer?.annotManager?.getAnnotationById(a.id));
if (this.viewer?.Core.annotationManager) {
return this._annotations.map(a => this.viewer?.Core.annotationManager?.getAnnotationById(a.id));
} else {
return [];
}
@ -78,15 +78,15 @@ export class AnnotationActionsComponent implements OnInit {
hideAnnotation($event: MouseEvent) {
$event.stopPropagation();
this.viewer.annotManager.hideAnnotations(this.viewerAnnotations);
this.viewer.annotManager.deselectAllAnnotations();
this.viewer.Core.annotationManager.hideAnnotations(this.viewerAnnotations);
this.viewer.Core.annotationManager.deselectAllAnnotations();
this.annotationActionsService.updateHiddenAnnotation(this.annotations, this.viewerAnnotations, true);
}
showAnnotation($event: MouseEvent) {
$event.stopPropagation();
this.viewer.annotManager.showAnnotations(this.viewerAnnotations);
this.viewer.annotManager.deselectAllAnnotations();
this.viewer.Core.annotationManager.showAnnotations(this.viewerAnnotations);
this.viewer.Core.annotationManager.deselectAllAnnotations();
this.annotationActionsService.updateHiddenAnnotation(this.annotations, this.viewerAnnotations, false);
}

View File

@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, S
import { ViewedPages, ViewedPagesControllerService } from '@redaction/red-ui-http';
import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { Subscription } from 'rxjs';
@Component({
@ -25,7 +25,7 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy {
constructor(
private readonly _viewedPagesControllerService: ViewedPagesControllerService,
private readonly _appStateService: AppStateService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _permissionService: PermissionsService
) {}
@ -67,11 +67,11 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy {
clearTimeout(this.pageReadTimeout);
}
if (this.active && !this.read) {
this.pageReadTimeout = setTimeout(() => {
this.pageReadTimeout = window.setTimeout(() => {
if (this.active && !this.read) {
this._markPageRead();
}
}, this._appConfigService.getConfig(AppConfigKey.AUTO_READ_TIME, 1.5) * 1000);
}, this._configService.values.AUTO_READ_TIME * 1000);
}
}
}

View File

@ -12,7 +12,7 @@ import {
ViewChild
} from '@angular/core';
import { ManualRedactionEntry } from '@redaction/red-ui-http';
import WebViewer, { Annotations, Tools, WebViewerInstance } from '@pdftron/webviewer';
import WebViewer, { Core, WebViewerInstance } from '@pdftron/webviewer';
import { TranslateService } from '@ngx-translate/core';
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
@ -23,7 +23,7 @@ import { AnnotationDrawService } from '../../services/annotation-draw.service';
import { AnnotationActionsService } from '../../services/annotation-actions.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { BASE_HREF } from '../../../../tokens';
import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { LoadingService } from '@iqser/common-ui';
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
@ -33,6 +33,8 @@ import { ViewMode } from '@models/file/view-mode';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { ActivatedRoute } from '@angular/router';
import TextTool = Tools.TextTool;
import Tools = Core.Tools;
import Annotation = Core.Annotations.Annotation;
@Component({
selector: 'redaction-pdf-viewer',
@ -71,7 +73,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
private readonly _userPreferenceService: UserPreferenceService,
private readonly _annotationDrawService: AnnotationDrawService,
private readonly _annotationActionsService: AnnotationActionsService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _loadingService: LoadingService
) {}
@ -107,11 +109,11 @@ export class PdfViewerComponent implements OnInit, OnChanges {
setInitialViewerState() {
// viewer init
this.instance.setFitMode('FitPage');
this.instance.UI.setFitMode('FitPage');
const instanceDisplayMode = this.instance.docViewer.getDisplayModeManager().getDisplayMode();
const instanceDisplayMode = this.instance.Core.documentViewer.getDisplayModeManager().getDisplayMode();
instanceDisplayMode.mode = this.viewMode === 'STANDARD' ? 'Single' : 'Facing';
this.instance.docViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
this.instance.Core.documentViewer.getDisplayModeManager().setDisplayMode(instanceDisplayMode);
}
async uploadFile(files: any) {
@ -123,13 +125,13 @@ export class PdfViewerComponent implements OnInit, OnChanges {
if (fileToCompare) {
fileReader.onload = async () => {
const pdfData = fileReader.result;
const pdfNet = this.instance.Core.PDFNet;
const PDFNet = this.instance.PDFNet;
await PDFNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
const mergedDocument = await PDFNet.PDFDoc.create();
const compareDocument = await PDFNet.PDFDoc.createFromBuffer(<any>pdfData);
const currentDocument = await PDFNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer());
const mergedDocument = await pdfNet.PDFDoc.create();
const compareDocument = await pdfNet.PDFDoc.createFromBuffer(<any>pdfData);
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer());
const currentDocumentPageCount = await currentDocument.getPageCount();
const compareDocumentPageCount = await compareDocument.getPageCount();
@ -151,7 +153,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
() => {
this.utils.navigateToPage(1);
},
PDFNet
this.instance.Core.PDFNet
);
this._loadingService.stop();
};
@ -182,14 +184,14 @@ export class PdfViewerComponent implements OnInit, OnChanges {
async closeCompareMode() {
this.viewMode = 'STANDARD';
const PDFNet = this.instance.PDFNet;
await PDFNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
const currentDocument = await PDFNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer());
this.instance.loadDocument(currentDocument, {
const pdfNet = this.instance.Core.PDFNet;
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.fileData.arrayBuffer());
this.instance.UI.loadDocument(currentDocument, {
filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf'
});
this.instance.disableElements(['closeCompareButton']);
this.instance.enableElements(['compareButton']);
this.instance.UI.disableElements(['closeCompareButton']);
this.instance.UI.enableElements(['compareButton']);
this.utils.navigateToPage(1);
}
@ -216,8 +218,8 @@ export class PdfViewerComponent implements OnInit, OnChanges {
this.utils.disableHotkeys();
this._configureTextPopup();
this.instance.annotManager.on('annotationSelected', (annotations, action) => {
this.annotationSelected.emit(this.instance.annotManager.getSelectedAnnotations().map(ann => ann.Id));
this.instance.Core.annotationManager.on('annotationSelected', (annotations, action) => {
this.annotationSelected.emit(this.instance.Core.annotationManager.getSelectedAnnotations().map(ann => ann.Id));
if (action === 'deselected') {
this._toggleRectangleAnnotationAction(true);
} else {
@ -226,16 +228,16 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
});
this.instance.annotManager.on('annotationChanged', annotations => {
this.instance.Core.annotationManager.on('annotationChanged', annotations => {
// when a rectangle is drawn,
// it returns one annotation with tool name 'AnnotationCreateRectangle;
// this will auto select rectangle after drawing
if (annotations.length === 1 && annotations[0].ToolName === 'AnnotationCreateRectangle') {
this.instance.annotManager.selectAnnotations(annotations);
this.instance.Core.annotationManager.selectAnnotations(annotations);
}
});
this.instance.docViewer.on('pageNumberUpdated', pageNumber => {
this.instance.Core.documentViewer.on('pageNumberUpdated', pageNumber => {
if (this.shouldDeselectAnnotationsOnPageChange) {
this.utils.deselectAllAnnotations();
}
@ -250,9 +252,9 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
});
this.instance.docViewer.on('documentLoaded', this._documentLoaded);
this.instance.Core.documentViewer.on('documentLoaded', this._documentLoaded);
this.instance.docViewer.on('keyUp', $event => {
this.instance.Core.documentViewer.on('keyUp', $event => {
// arrows and full-screen
if ($event.target?.tagName?.toLowerCase() !== 'input') {
if ($event.key.startsWith('Arrow') || $event.key === 'f') {
@ -270,23 +272,23 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
});
this.instance.docViewer.on('textSelected', (quads, selectedText) => {
this.instance.Core.documentViewer.on('textSelected', (quads, selectedText) => {
this._selectedText = selectedText;
if (selectedText.length > 2 && this.canPerformActions) {
this.instance.enableElements(['add-dictionary', 'add-false-positive']);
this.instance.UI.enableElements(['add-dictionary', 'add-false-positive']);
} else {
this.instance.disableElements(['add-dictionary', 'add-false-positive']);
this.instance.UI.disableElements(['add-dictionary', 'add-false-positive']);
}
});
this.instance.iframeWindow.addEventListener('visibilityChanged', (event: any) => {
this.instance.UI.iframeWindow.addEventListener('visibilityChanged', (event: any) => {
if (event.detail.element === 'searchPanel') {
const inputElement = this.instance.iframeWindow.document.getElementById('SearchPanel__input') as HTMLInputElement;
const inputElement = this.instance.UI.iframeWindow.document.getElementById('SearchPanel__input') as HTMLInputElement;
setTimeout(() => {
inputElement.value = '';
}, 0);
if (!event.detail.isVisible) {
this.instance.docViewer.clearSearchResults();
this.instance.Core.documentViewer.clearSearchResults();
}
}
});
@ -295,20 +297,20 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
private _setSelectionMode(): void {
const textTool = (<unknown>this.instance.Tools.TextTool) as TextTool;
textTool.SELECTION_MODE = this._appConfigService.getConfig(AppConfigKey.SELECTION_MODE);
const textTool = (<unknown>this.instance.Core.Tools.TextTool) as TextTool;
textTool.SELECTION_MODE = this._configService.values.SELECTION_MODE;
}
private _toggleRectangleAnnotationAction(readonly: boolean) {
if (!readonly) {
this.instance.enableElements(['add-rectangle']);
this.instance.UI.enableElements(['add-rectangle']);
} else {
this.instance.disableElements(['add-rectangle']);
this.instance.UI.disableElements(['add-rectangle']);
}
}
private _disableElements() {
this.instance.disableElements([
this.instance.UI.disableElements([
'pageNavOverlay',
'menuButton',
'selectToolButton',
@ -331,7 +333,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
'annotationGroupButton'
]);
this.instance.setHeaderItems(header => {
this.instance.UI.setHeaderItems(header => {
const originalHeaderItems = header.getItems();
originalHeaderItems.splice(8, 0, {
type: 'divider',
@ -372,9 +374,9 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
});
this.instance.disableElements(['closeCompareButton']);
this.instance.UI.disableElements(['closeCompareButton']);
this.instance.docViewer.getTool('AnnotationCreateRectangle').setStyles(() => ({
this.instance.Core.documentViewer.getTool('AnnotationCreateRectangle').setStyles(() => ({
StrokeThickness: 2,
StrokeColor: this._annotationDrawService.getColor(this.instance, 'manual'),
FillColor: this._annotationDrawService.getColor(this.instance, 'manual'),
@ -382,13 +384,13 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}));
}
private _configureAnnotationSpecificActions(viewerAnnotations: Annotations.Annotation[]) {
private _configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) {
if (!this.canPerformActions) {
return;
}
const annotationWrappers = viewerAnnotations.map(va => this.annotations.find(a => a.id === va.Id)).filter(va => !!va);
this.instance.annotationPopup.update([]);
this.instance.UI.annotationPopup.update([]);
if (annotationWrappers.length === 0) {
this._configureRectangleAnnotationPopup();
@ -400,7 +402,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
if (allAnnotationsHaveImageAction) {
const allAreVisible = viewerAnnotations.reduce((acc, next) => next.isVisible() && acc, true);
this.instance.annotationPopup.add([
this.instance.UI.annotationPopup.add([
{
type: 'actionButton',
img: allAreVisible
@ -410,11 +412,11 @@ export class PdfViewerComponent implements OnInit, OnChanges {
onClick: () => {
this._ngZone.run(() => {
if (allAreVisible) {
this.instance.annotManager.hideAnnotations(viewerAnnotations);
this.instance.Core.annotationManager.hideAnnotations(viewerAnnotations);
} else {
this.instance.annotManager.showAnnotations(viewerAnnotations);
this.instance.Core.annotationManager.showAnnotations(viewerAnnotations);
}
this.instance.annotManager.deselectAllAnnotations();
this.instance.Core.annotationManager.deselectAllAnnotations();
this._annotationActionsService.updateHiddenAnnotation(this.annotations, viewerAnnotations, allAreVisible);
});
}
@ -422,19 +424,19 @@ export class PdfViewerComponent implements OnInit, OnChanges {
]);
}
this.instance.annotationPopup.add(
this.instance.UI.annotationPopup.add(
this._annotationActionsService.getViewerAvailableActions(annotationWrappers, this.annotationsChanged)
);
}
private _configureRectangleAnnotationPopup() {
this.instance.annotationPopup.add(<any>{
this.instance.UI.annotationPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-rectangle',
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('REDACTION')),
onClick: () => {
const selectedAnnotations = this.instance.annotManager.getSelectedAnnotations();
const selectedAnnotations = this.instance.Core.annotationManager.getSelectedAnnotations();
const activeAnnotation = selectedAnnotations[0];
const activePage = selectedAnnotations[0].getPageNumber();
const quad = this._annotationDrawService.annotationToQuads(activeAnnotation, this.instance);
@ -443,8 +445,8 @@ export class PdfViewerComponent implements OnInit, OnChanges {
const mre = this._getManualRedactionEntry(quadsObject, 'Rectangle');
// cleanup selection and button state
this.utils.deselectAllAnnotations();
this.instance.disableElements(['shapeToolGroupButton', 'rectangleToolDivider']);
this.instance.enableElements(['shapeToolGroupButton', 'rectangleToolDivider']);
this.instance.UI.disableElements(['shapeToolGroupButton', 'rectangleToolDivider']);
this.instance.UI.enableElements(['shapeToolGroupButton', 'rectangleToolDivider']);
// dispatch event
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper([quad], mre, 'REDACTION', 'RECTANGLE', activeAnnotation.Id)
@ -454,12 +456,12 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
private _configureTextPopup() {
this.instance.textPopup.add(<any>{
this.instance.UI.textPopup.add(<any>{
type: 'actionButton',
img: this._convertPath('/assets/icons/general/pdftron-action-search.svg'),
title: this._translateService.instant('pdf-viewer.text-popup.actions.search'),
onClick: () => {
const text = this.instance.docViewer.getSelectedText();
const text = this.instance.Core.documentViewer.getSelectedText();
const searchOptions = {
caseSensitive: true, // match case
wholeWord: true, // match whole words only
@ -468,57 +470,57 @@ export class PdfViewerComponent implements OnInit, OnChanges {
searchUp: false, // search from the end of the document upwards
ambientString: true // return ambient string as part of the result
};
this.instance.openElements(['searchPanel']);
this.instance.UI.openElements(['searchPanel']);
setTimeout(() => {
this.instance.searchTextFull(text, searchOptions);
this.instance.UI.searchTextFull(text, searchOptions);
}, 250);
}
});
// Adding directly to the false-positive dict is only available in dev-mode
if (this._userPreferenceService.areDevFeaturesEnabled) {
this.instance.textPopup.add(<any>{
this.instance.UI.textPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-false-positive',
img: this._convertPath('/assets/icons/general/pdftron-action-false-positive.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('FALSE_POSITIVE')),
onClick: () => {
const selectedQuads = this.instance.docViewer.getSelectedTextQuads();
const text = this.instance.docViewer.getSelectedText();
const selectedQuads = this.instance.Core.documentViewer.getSelectedTextQuads();
const text = this.instance.Core.documentViewer.getSelectedText();
const mre = this._getManualRedactionEntry(selectedQuads, text, true);
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper(this.instance.docViewer.getSelectedTextQuads(), mre, 'FALSE_POSITIVE')
new ManualRedactionEntryWrapper(this.instance.Core.documentViewer.getSelectedTextQuads(), mre, 'FALSE_POSITIVE')
);
}
});
}
this.instance.textPopup.add(<any>{
this.instance.UI.textPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-dictionary',
img: this._convertPath('/assets/icons/general/pdftron-action-add-dict.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('DICTIONARY')),
onClick: () => {
const selectedQuads = this.instance.docViewer.getSelectedTextQuads();
const text = this.instance.docViewer.getSelectedText();
const selectedQuads = this.instance.Core.documentViewer.getSelectedTextQuads();
const text = this.instance.Core.documentViewer.getSelectedText();
const mre = this._getManualRedactionEntry(selectedQuads, text, true);
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper(this.instance.docViewer.getSelectedTextQuads(), mre, 'DICTIONARY')
new ManualRedactionEntryWrapper(this.instance.Core.documentViewer.getSelectedTextQuads(), mre, 'DICTIONARY')
);
}
});
this.instance.textPopup.add(<any>{
this.instance.UI.textPopup.add(<any>{
type: 'actionButton',
dataElement: 'add-redaction',
img: this._convertPath('/assets/icons/general/pdftron-action-add-redaction.svg'),
title: this._translateService.instant(this._manualAnnotationService.getTitle('REDACTION')),
onClick: () => {
const selectedQuads = this.instance.docViewer.getSelectedTextQuads();
const text = this.instance.docViewer.getSelectedText();
const selectedQuads = this.instance.Core.documentViewer.getSelectedTextQuads();
const text = this.instance.Core.documentViewer.getSelectedText();
const mre = this._getManualRedactionEntry(selectedQuads, text, true);
this.manualAnnotationRequested.emit(
new ManualRedactionEntryWrapper(this.instance.docViewer.getSelectedTextQuads(), mre, 'REDACTION')
new ManualRedactionEntryWrapper(this.instance.Core.documentViewer.getSelectedTextQuads(), mre, 'REDACTION')
);
}
});
@ -526,10 +528,10 @@ export class PdfViewerComponent implements OnInit, OnChanges {
}
private _handleCustomActions() {
this.instance.setToolMode('AnnotationEdit');
this.instance.UI.setToolMode('AnnotationEdit');
if (this.canPerformActions) {
this.instance.enableTools(['AnnotationCreateRectangle']);
this.instance.enableElements([
this.instance.UI.enableTools(['AnnotationCreateRectangle']);
this.instance.UI.enableElements([
'add-redaction',
'add-rectangle',
'add-false-positive',
@ -538,11 +540,11 @@ export class PdfViewerComponent implements OnInit, OnChanges {
'annotationPopup'
]);
if (this._selectedText.length > 2) {
this.instance.enableElements(['add-dictionary', 'add-false-positive']);
this.instance.UI.enableElements(['add-dictionary', 'add-false-positive']);
}
} else {
this.instance.disableTools(['AnnotationCreateRectangle']);
this.instance.disableElements([
this.instance.UI.disableTools(['AnnotationCreateRectangle']);
this.instance.UI.disableElements([
'add-redaction',
'add-dictionary',
'add-false-positive',
@ -568,7 +570,7 @@ export class PdfViewerComponent implements OnInit, OnChanges {
private _loadDocument() {
if (this.fileData) {
this.instance.loadDocument(this.fileData, {
this.instance.UI.loadDocument(this.fileData, {
filename: this.fileStatus ? this.fileStatus.filename : 'document.pdf'
});
}

View File

@ -13,7 +13,7 @@ import {
import { FileManagementControllerService, FileStatus, StatusControllerService } from '@redaction/red-ui-http';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import * as moment from 'moment';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { getLeftDateTime } from '@utils/functions';
import { Observable } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';
@ -44,7 +44,7 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
tableColumnConfigs: TableColumnConfig<FileListItem>[];
readonly tableHeaderLabel = _('edit-dossier-dialog.deleted-documents.table-header.label');
readonly circleButtonTypes = CircleButtonTypes;
readonly deleteRetentionHours = this._appConfigService.getConfig(AppConfigKey.DELETE_RETENTION_HOURS);
readonly deleteRetentionHours = this._configService.values.DELETE_RETENTION_HOURS;
@ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef<never>;
@ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef<never>;
@ViewChild('deletedDateTemplate', { static: true }) deletedDateTemplate: TemplateRef<never>;
@ -57,7 +57,7 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
private readonly _fileManagementController: FileManagementControllerService,
private readonly _appStateService: AppStateService,
private readonly _loadingService: LoadingService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _dialogService: DossiersDialogService
) {
super(_injector);

View File

@ -27,7 +27,7 @@ import { StatusSorter } from '@utils/sorters/status-sorter';
import { convertFiles, handleFileDrop } from '@utils/file-drop-utils';
import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { ActionConfig } from '@shared/components/page-header/models/action-config.model';
import {
CircleButtonTypes,
@ -50,7 +50,7 @@ import { annotationFilterChecker } from '@utils/filter-utils';
import { PermissionsService } from '@services/permissions.service';
import { RouterHistoryService } from '@services/router-history.service';
import { FileAttributeConfig } from '@redaction/red-ui-http';
import { DossierWrapper } from '../../../../state/model/dossier.wrapper';
import { DossierWrapper } from '@state/model/dossier.wrapper';
@Component({
templateUrl: './dossier-overview-screen.component.html',
@ -98,7 +98,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
private readonly _loadingService: LoadingService,
private readonly _appStateService: AppStateService,
readonly routerHistoryService: RouterHistoryService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _translateService: TranslateService,
private readonly _dialogService: DossiersDialogService,
private readonly _changeDetectorRef: ChangeDetectorRef,
@ -256,7 +256,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
}
recentlyModifiedChecker = (file: FileStatusWrapper) =>
moment(file.lastUpdated).add(this._appConfigService.getConfig(AppConfigKey.RECENT_PERIOD_IN_HOURS), 'hours').isAfter(moment());
moment(file.lastUpdated).add(this._configService.values.RECENT_PERIOD_IN_HOURS, 'hours').isAfter(moment());
private _configureTableColumns() {
const dynamicColumns: TableColumnConfig<FileStatusWrapper>[] = [];
@ -472,7 +472,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
private _createQuickFilters() {
let quickFilters = [];
if (this.entitiesService.all.filter(this.recentlyModifiedChecker).length > 0) {
const recentPeriod = this._appConfigService.getConfig(AppConfigKey.RECENT_PERIOD_IN_HOURS);
const recentPeriod = this._configService.values.RECENT_PERIOD_IN_HOURS;
quickFilters = [
{
key: 'recent',

View File

@ -1,7 +1,7 @@
import { ChangeDetectorRef, Component, HostListener, NgZone, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ActivatedRoute, ActivatedRouteSnapshot, NavigationExtras, Router } from '@angular/router';
import { AppStateService } from '@state/app-state.service';
import { Annotations, WebViewerInstance } from '@pdftron/webviewer';
import { Core, WebViewerInstance } from '@pdftron/webviewer';
import { PdfViewerComponent } from '../../components/pdf-viewer/pdf-viewer.component';
import {
AutoUnsubscribe,
@ -43,6 +43,7 @@ import { TranslateService } from '@ngx-translate/core';
import { fileStatusTranslations } from '../../translations/file-status-translations';
import { handleFilterDelta } from '@utils/filter-utils';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import Annotation = Core.Annotations.Annotation;
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f'];
@ -131,7 +132,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
get activeViewerPage(): number {
const currentPage = this._instance?.docViewer?.getCurrentPage();
const currentPage = this._instance?.Core.documentViewer?.getCurrentPage();
if (!currentPage) {
return 0;
}
@ -262,9 +263,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
rebuildFilters(deletePreviousAnnotations = false): void {
const startTime = new Date().getTime();
if (deletePreviousAnnotations) {
const annotationsToDelete = this._instance?.annotManager?.getAnnotationsList() || [];
const annotationsToDelete = this._instance?.Core.annotationManager?.getAnnotationsList() || [];
try {
this._instance?.annotManager?.deleteAnnotations(annotationsToDelete, {
this._instance?.Core.annotationManager?.deleteAnnotations(annotationsToDelete, {
imported: true,
force: true
});
@ -344,8 +345,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
entryWrapper,
async (response: ManualAnnotationResponse) => {
if (response?.annotationId) {
const annotation = this._instance.annotManager.getAnnotationById(response.manualRedactionEntryWrapper.rectId);
this._instance.annotManager.deleteAnnotation(annotation);
const annotation = this._instance.Core.annotationManager.getAnnotationById(
response.manualRedactionEntryWrapper.rectId
);
this._instance.Core.annotationManager.deleteAnnotation(annotation);
this.fileData.fileStatus = await this.appStateService.reloadActiveFile();
const distinctPages = entryWrapper.manualRedactionEntry.positions
.map(p => p.page)
@ -550,11 +553,12 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
private async _doStampExcludedPages(excludedPages: number[]) {
if (excludedPages && excludedPages.length > 0) {
const document = await this._instance.docViewer.getDocument().getPDFDoc();
await clearStamps(document, this._instance.PDFNet, [...Array(this.fileData.fileStatus.numberOfPages).keys()]);
const pdfNet = this._instance.Core.PDFNet;
const document = await this._instance.Core.documentViewer.getDocument().getPDFDoc();
await clearStamps(document, pdfNet, [...Array(this.fileData.fileStatus.numberOfPages).keys()]);
await stampPDFPage(
document,
this._instance.PDFNet,
pdfNet,
this._translateService.instant('file-preview.excluded-from-redaction'),
25,
'courier',
@ -568,8 +572,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
private async _stampExcludedPages() {
await this._doStampExcludedPages(this.fileData.fileStatus.excludedPages);
this._instance.docViewer.refreshAll();
this._instance.docViewer.updateView([this.activeViewerPage], this.activeViewerPage);
this._instance.Core.documentViewer.refreshAll();
this._instance.Core.documentViewer.updateView([this.activeViewerPage], this.activeViewerPage);
this._changeDetectorRef.detectChanges();
}
@ -678,9 +682,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
private _findAndDeleteAnnotation(id: string) {
const viewerAnnotation = this._instance.annotManager.getAnnotationById(id);
const viewerAnnotation = this._instance.Core.annotationManager.getAnnotationById(id);
if (viewerAnnotation) {
this._instance.annotManager.deleteAnnotation(viewerAnnotation, {
this._instance.Core.annotationManager.deleteAnnotation(viewerAnnotation, {
imported: true,
force: true
});
@ -701,16 +705,16 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
private _getAnnotations(predicate: (value) => unknown) {
const annotations = this._instance.annotManager.getAnnotationsList();
const annotations = this._instance.Core.annotationManager.getAnnotationsList();
return predicate ? annotations.filter(predicate) : annotations;
}
private _hide(annotations: Annotations.Annotation[]): void {
this._instance.annotManager.hideAnnotations(annotations);
private _hide(annotations: Annotation[]): void {
this._instance.Core.annotationManager.hideAnnotations(annotations);
}
private _show(annotations: Annotations.Annotation[]): void {
this._instance.annotManager.showAnnotations(annotations);
private _show(annotations: Annotation[]): void {
this._instance.Core.annotationManager.showAnnotations(annotations);
}
private _setAnnotationsColor(annotations, customData: string) {

View File

@ -10,7 +10,8 @@ import { AnnotationPermissions } from '@models/file/annotation.permissions';
import { DossiersDialogService } from './dossiers-dialog.service';
import { BASE_HREF } from '../../../tokens';
import { UserService } from '@services/user.service';
import { Annotations } from '@pdftron/webviewer';
import { Core } from '@pdftron/webviewer';
import Annotation = Core.Annotations.Annotation;
@Injectable()
export class AnnotationActionsService {
@ -281,7 +282,7 @@ export class AnnotationActionsService {
return availableActions;
}
updateHiddenAnnotation(annotations: AnnotationWrapper[], viewerAnnotations: Annotations.Annotation[], hidden: boolean) {
updateHiddenAnnotation(annotations: AnnotationWrapper[], viewerAnnotations: Annotation[], hidden: boolean) {
const annotationId = (viewerAnnotations[0] as any).Tw;
const annotationToBeUpdated = annotations.find((a: AnnotationWrapper) => a.annotationId === annotationId);
annotationToBeUpdated.hidden = hidden;

View File

@ -1,10 +1,11 @@
import { Injectable } from '@angular/core';
import { Annotations, WebViewerInstance } from '@pdftron/webviewer';
import { Core, WebViewerInstance } from '@pdftron/webviewer';
import { Rectangle, RedactionLogControllerService, SectionGrid, SectionRectangle } from '@redaction/red-ui-http';
import { hexToRgb } from '@utils/functions';
import { AppStateService } from '@state/app-state.service';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { UserPreferenceService } from '@services/user-preference.service';
import Annotation = Core.Annotations.Annotation;
@Injectable()
export class AnnotationDrawService {
@ -14,18 +15,13 @@ export class AnnotationDrawService {
private readonly _userPreferenceService: UserPreferenceService
) {}
drawAnnotations(
activeViewer: WebViewerInstance,
annotationWrappers: AnnotationWrapper[],
hideSkipped: boolean = false,
compareMode: boolean = false
) {
drawAnnotations(activeViewer: WebViewerInstance, annotationWrappers: AnnotationWrapper[], hideSkipped = false, compareMode = false) {
const annotations = [];
annotationWrappers.forEach(annotation => {
annotations.push(this.computeAnnotation(activeViewer, annotation, hideSkipped, compareMode));
});
const annotationManager = activeViewer.annotManager;
const annotationManager = activeViewer.Core.annotationManager;
annotationManager.addAnnotations(annotations, { imported: true });
annotationManager.drawAnnotationsFromList(annotations);
@ -49,14 +45,14 @@ export class AnnotationDrawService {
// })
});
}
const annotationManager = activeViewer.annotManager;
const annotationManager = activeViewer.Core.annotationManager;
annotationManager.addAnnotations(sections, { imported: true });
annotationManager.drawAnnotationsFromList(sections);
}
computeSection(activeViewer: WebViewerInstance, pageNumber: number, sectionRectangle: SectionRectangle) {
const rectangleAnnot = new activeViewer.Annotations.RectangleAnnotation();
const pageHeight = activeViewer.docViewer.getPageHeight(pageNumber);
const rectangleAnnot = new activeViewer.Core.Annotations.RectangleAnnotation();
const pageHeight = activeViewer.Core.documentViewer.getPageHeight(pageNumber);
const rectangle = {
topLeft: sectionRectangle.topLeft,
page: pageNumber,
@ -75,14 +71,9 @@ export class AnnotationDrawService {
return rectangleAnnot;
}
computeAnnotation(
activeViewer: WebViewerInstance,
annotationWrapper: AnnotationWrapper,
hideSkipped: boolean = false,
compareMode: boolean = false
) {
computeAnnotation(activeViewer: WebViewerInstance, annotationWrapper: AnnotationWrapper, hideSkipped = false, compareMode = false) {
const pageNumber = compareMode ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber;
const highlight = new activeViewer.Annotations.TextHighlightAnnotation();
const highlight = new activeViewer.Core.Annotations.TextHighlightAnnotation();
highlight.PageNumber = pageNumber;
highlight.StrokeColor = this.getColor(activeViewer, annotationWrapper.superType, annotationWrapper.type);
highlight.setContents(annotationWrapper.content);
@ -96,13 +87,16 @@ export class AnnotationDrawService {
(hideSkipped && annotationWrapper.isSkipped) ||
annotationWrapper.isOCR ||
annotationWrapper.hidden;
highlight.setCustomData('redacto-manager', true);
highlight.setCustomData('redaction', annotationWrapper.isRedacted);
highlight.setCustomData('skipped', annotationWrapper.isSkipped);
highlight.setCustomData('changeLog', annotationWrapper.isChangeLogEntry);
highlight.setCustomData('changeLogRemoved', annotationWrapper.isChangeLogRemoved);
highlight.setCustomData('redactionColor', this.getColor(activeViewer, 'redaction', 'redaction'));
highlight.setCustomData('annotationColor', this.getColor(activeViewer, annotationWrapper.superType, annotationWrapper.type));
highlight.setCustomData('redacto-manager', 'true');
highlight.setCustomData('redaction', String(annotationWrapper.isRedacted));
highlight.setCustomData('skipped', String(annotationWrapper.isSkipped));
highlight.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry));
highlight.setCustomData('changeLogRemoved', String(annotationWrapper.isChangeLogRemoved));
highlight.setCustomData('redactionColor', String(this.getColor(activeViewer, 'redaction', 'redaction')));
highlight.setCustomData(
'annotationColor',
String(this.getColor(activeViewer, annotationWrapper.superType, annotationWrapper.type))
);
return highlight;
}
@ -123,10 +117,10 @@ export class AnnotationDrawService {
break;
}
const rgbColor = hexToRgb(color);
return new activeViewer.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b);
return new activeViewer.Core.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b);
}
annotationToQuads(annotation: Annotations.Annotation, activeViewer: WebViewerInstance) {
annotationToQuads(annotation: Annotation, activeViewer: WebViewerInstance) {
const x1 = annotation.getRect().x1;
const y1 = annotation.getRect().y1 + annotation.getRect().getHeight();
@ -139,11 +133,11 @@ export class AnnotationDrawService {
const x4 = annotation.getRect().x1;
const y4 = annotation.getRect().y1;
return new activeViewer.CoreControls.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4);
return new activeViewer.Core.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4);
}
private _rectanglesToQuads(positions: Rectangle[], activeViewer: WebViewerInstance, pageNumber: number): any[] {
const pageHeight = activeViewer.docViewer.getPageHeight(pageNumber);
const pageHeight = activeViewer.Core.documentViewer.getPageHeight(pageNumber);
return positions.map(p => this._rectangleToQuad(p, activeViewer, pageHeight));
}
@ -160,6 +154,6 @@ export class AnnotationDrawService {
const x4 = rectangle.topLeft.x;
const y4 = pageHeight - rectangle.topLeft.y;
return new activeViewer.CoreControls.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4);
return new activeViewer.Core.Math.Quad(x1, y1, x2, y2, x3, y3, x4, y4);
}
}

View File

@ -10,7 +10,7 @@ import { ManualAnnotationService } from './manual-annotation.service';
import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
import { EditDossierDialogComponent } from '../dialogs/edit-dossier-dialog/edit-dossier-dialog.component';
import { AssignReviewerApproverDialogComponent } from '../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
import { AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { ChangeLegalBasisDialogComponent } from '../dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component';
import { RecategorizeImageDialogComponent } from '../dialogs/recategorize-image-dialog/recategorize-image-dialog.component';
import { DialogService, largeDialogConfig } from '@shared/services/dialog.service';
@ -78,7 +78,7 @@ export class DossiersDialogService extends DialogService<DialogType> {
protected readonly _dialog: MatDialog,
private readonly _appStateService: AppStateService,
private readonly _manualAnnotationService: ManualAnnotationService,
private readonly _appConfigService: AppConfigService
private readonly _configService: ConfigService
) {
super(_dialog);
}

View File

@ -1,15 +1,15 @@
import { stampPDFPage } from '../../../utils/page-stamper';
import { stampPDFPage } from '@utils/page-stamper';
const processPage = async (pageNumber, document1, document2, mergedDocument, PDFNet) => {
const processPage = async (pageNumber, document1, document2, mergedDocument, pdfNet) => {
const document1PageCount = await document1.getPageCount();
if (document1PageCount >= pageNumber) {
await mergedDocument.insertPages(pageNumber * 2, document1, pageNumber, pageNumber, PDFNet.PDFDoc.InsertFlag.e_none);
await mergedDocument.insertPages(pageNumber * 2, document1, pageNumber, pageNumber, pdfNet.PDFDoc.InsertFlag.e_none);
} else {
const pageToCopy = await document2.getPage(pageNumber);
const blankPage = await mergedDocument.pageCreate(await pageToCopy.getCropBox());
await blankPage.setRotation(await pageToCopy.getRotation());
await mergedDocument.pagePushBack(blankPage);
await stampPDFPage(mergedDocument, PDFNet, '<< Compare Placeholder Page >>', 20, 'courier', 'DIAGONAL', 33, '#ffb83b', [
await stampPDFPage(mergedDocument, pdfNet, '<< Compare Placeholder Page >>', 20, 'courier', 'DIAGONAL', 33, '#ffb83b', [
await mergedDocument.getPageCount()
]);
}
@ -25,17 +25,17 @@ export const loadCompareDocumentWrapper = async (
fileStatus,
setCompareViewMode: () => void,
navigateToPage: () => void,
PDFNet
pdfNet: any
) => {
try {
const maxPageCount = Math.max(currentDocumentPageCount, compareDocumentPageCount);
for (let idx = 1; idx <= maxPageCount; idx++) {
await processPage(idx, currentDocument, compareDocument, mergedDocument, PDFNet);
await processPage(idx, compareDocument, currentDocument, mergedDocument, PDFNet);
await processPage(idx, currentDocument, compareDocument, mergedDocument, pdfNet);
await processPage(idx, compareDocument, currentDocument, mergedDocument, pdfNet);
}
const buffer = await mergedDocument.saveMemoryBuffer(PDFNet.SDFDoc.SaveOptions.e_linearized);
const buffer = await mergedDocument.saveMemoryBuffer(pdfNet.SDFDoc.SaveOptions.e_linearized);
const mergedDocumentBuffer = new Blob([buffer], {
type: 'application/pdf'

View File

@ -1,8 +1,9 @@
import { Annotations, WebViewerInstance } from '@pdftron/webviewer';
import { ViewMode } from '@models/file/view-mode';
import { translateQuads } from '../../../utils/pdf-coordinates';
import { translateQuads } from '@utils/pdf-coordinates';
import { Rectangle } from '@redaction/red-ui-http';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { Core, WebViewerInstance } from '@pdftron/webviewer';
import Annotation = Core.Annotations.Annotation;
const DISABLED_HOTKEYS = [
'CTRL+SHIFT+EQUAL',
@ -35,18 +36,19 @@ const DISABLED_HOTKEYS = [
'H',
'K',
'U'
];
] as const;
export class PdfViewerUtils {
instance: WebViewerInstance;
viewMode: ViewMode;
ready = false;
multiSelectActive: boolean;
constructor(instance: WebViewerInstance, viewMode: ViewMode, multiSelectActive: boolean) {
this.instance = instance;
this.viewMode = viewMode;
this.multiSelectActive = multiSelectActive;
constructor(readonly instance: WebViewerInstance, public viewMode: ViewMode, public multiSelectActive: boolean) {}
private get _documentViewer() {
return this.instance?.Core.documentViewer;
}
private get _annotationManager() {
return this.instance?.Core.annotationManager;
}
get isCompareMode() {
@ -59,9 +61,7 @@ export class PdfViewerUtils {
get currentPage() {
try {
return this.isCompareMode
? Math.ceil(this.instance?.docViewer?.getCurrentPage() / 2)
: this.instance?.docViewer?.getCurrentPage();
return this.isCompareMode ? Math.ceil(this._currentInternalPage / 2) : this._currentInternalPage;
} catch (e) {
return null;
}
@ -73,18 +73,18 @@ export class PdfViewerUtils {
}
try {
return this.isCompareMode ? Math.ceil(this.instance?.docViewer?.getPageCount() / 2) : this.instance?.docViewer?.getPageCount();
return this.isCompareMode ? Math.ceil(this._totalInternalPages / 2) : this._totalInternalPages;
} catch (e) {
return null;
}
}
private get _currentInternalPage() {
return this.instance?.docViewer?.getCurrentPage();
return this.instance?.Core.documentViewer?.getCurrentPage();
}
private get _totalInternalPages() {
return this.instance?.docViewer?.getPageCount();
return this.instance?.Core.documentViewer?.getPageCount();
}
navigateToPage(pageNumber: string | number) {
@ -106,17 +106,17 @@ export class PdfViewerUtils {
disableHotkeys(): void {
for (const hotkey of DISABLED_HOTKEYS) {
this.instance.hotkeys.off(hotkey);
this.instance.UI.hotkeys.off(hotkey);
}
}
translateQuads(page: number, quads: any) {
const rotation = this.instance.docViewer.getCompleteRotation(page);
const rotation = this._documentViewer.getCompleteRotation(page);
return translateQuads(page, rotation, quads);
}
toPosition(page: number, selectedQuad: any): Rectangle {
const pageHeight = this.instance.docViewer.getPageHeight(page);
const pageHeight = this._documentViewer.getPageHeight(page);
const height = selectedQuad.y2 - selectedQuad.y4;
return {
page: page,
@ -130,7 +130,7 @@ export class PdfViewerUtils {
}
deselectAllAnnotations() {
this.instance.annotManager.deselectAllAnnotations();
this._annotationManager.deselectAllAnnotations();
}
selectAnnotations($event: AnnotationWrapper[] | { annotations: AnnotationWrapper[]; multiSelect: boolean }) {
@ -149,24 +149,23 @@ export class PdfViewerUtils {
}
const annotationsFromViewer = annotations.map(ann => this._getAnnotationById(ann.id));
this.instance.annotManager.selectAnnotations(annotationsFromViewer);
this._annotationManager.selectAnnotations(annotationsFromViewer);
// this.navigateToPage(annotations[0].pageNumber*this.paginationOffset);
this.instance.annotManager.jumpToAnnotation(annotationsFromViewer[0]);
this._annotationManager.jumpToAnnotation(annotationsFromViewer[0]);
}
deselectAnnotations(annotations: AnnotationWrapper[]) {
const ann = annotations.map(a => this._getAnnotationById(a.id));
this.instance.annotManager.deselectAnnotations(ann);
this._annotationManager.deselectAnnotations(ann);
}
private _navigateToPage(pageNumber) {
const activePage = this.instance.docViewer.getCurrentPage();
if (activePage !== pageNumber) {
this.instance.docViewer.displayPageLocation(pageNumber, 0, 0);
if (this._currentInternalPage !== pageNumber) {
this._documentViewer.displayPageLocation(pageNumber, 0, 0);
}
}
private _getAnnotationById(id: string): Annotations.Annotation {
return this.instance.annotManager.getAnnotationById(id);
private _getAnnotationById(id: string): Annotation {
return this._annotationManager.getAnnotationById(id);
}
}

View File

@ -1,7 +1,7 @@
import { ApplicationRef, Injectable } from '@angular/core';
import { DownloadControllerService, FileManagementControllerService } from '@redaction/red-ui-http';
import { interval, Observable } from 'rxjs';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { TranslateService } from '@ngx-translate/core';
import { DossierWrapper } from '@state/model/dossier.wrapper';
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
@ -23,7 +23,7 @@ export class FileDownloadService {
private readonly _keycloakService: KeycloakService,
private readonly _appStateService: AppStateService,
private readonly _translateService: TranslateService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _downloadControllerService: DownloadControllerService,
private readonly _fileManagementControllerService: FileManagementControllerService
) {
@ -56,7 +56,7 @@ export class FileDownloadService {
const token = await this._keycloakService.getToken();
const anchor = document.createElement('a');
anchor.href =
this._appConfigService.getConfig(AppConfigKey.API_URL) +
this._configService.values.API_URL +
'/async/download?access_token=' +
encodeURIComponent(token) +
'&storageId=' +

View File

@ -3,7 +3,7 @@ import { FileUploadModel } from '../model/file-upload.model';
import { AppStateService } from '@state/app-state.service';
import { HttpErrorResponse, HttpEventType } from '@angular/common/http';
import { interval, Subscription } from 'rxjs';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { TranslateService } from '@ngx-translate/core';
import { UploadDownloadDialogService } from './upload-download-dialog.service';
import { toNumber } from '@utils/functions';
@ -30,7 +30,7 @@ export class FileUploadService {
private readonly _appStateService: AppStateService,
private readonly _applicationRef: ApplicationRef,
private readonly _translateService: TranslateService,
private readonly _appConfigService: AppConfigService,
private readonly _configService: ConfigService,
private readonly _uploadControllerService: UploadControllerService,
private readonly _dialogService: UploadDownloadDialogService,
private readonly _errorMessageService: ErrorMessageService
@ -55,10 +55,10 @@ export class FileUploadService {
}
async uploadFiles(files: FileUploadModel[]): Promise<number> {
const maxSizeMB = this._appConfigService.getConfig(AppConfigKey.MAX_FILE_SIZE_MB, 100);
const maxSizeMB = this._configService.values.MAX_FILE_SIZE_MB;
const maxSizeBytes = toNumber(maxSizeMB) * 1024 * 1024;
const dossierFiles = this._appStateService.activeDossier.files;
let option: 'overwrite' | 'skip' | undefined;
let option: 'overwrite' | 'skip';
for (let idx = 0; idx < files.length; ++idx) {
const file = files[idx];
let currentOption = option;

View File

@ -22,7 +22,7 @@ export class UploadStatusOverlayComponent implements OnInit {
) {}
ngOnInit() {
this.uploadStatusInterval = setInterval(() => {
this.uploadStatusInterval = window.setInterval(() => {
// keep only errors
this.uploadService.filterFiles();
if (this.uploadService.files.length === 0) {

View File

@ -0,0 +1,43 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Title } from '@angular/platform-browser';
import packageInfo from '../../../../../package.json';
import config from '../../assets/config/config.json';
import { CacheApiService, wipeCaches } from '@redaction/red-cache';
const version = packageInfo.version;
@Injectable({
providedIn: 'root'
})
export class ConfigService {
private _values = { ...config, FRONTEND_APP_VERSION: version } as const;
constructor(
private readonly _httpClient: HttpClient,
private readonly _cacheApiService: CacheApiService,
private readonly _titleService: Title
) {
this._checkFrontendVersion();
}
private _checkFrontendVersion(): void {
this._cacheApiService.getCachedValue('FRONTEND_APP_VERSION').then(async lastVersion => {
console.log('[REDACTION] Last app version: ', lastVersion, ' current version ', version);
if (lastVersion !== version) {
console.warn('[REDACTION] Version-mismatch - wiping caches!');
await wipeCaches();
}
await this._cacheApiService.cacheValue('FRONTEND_APP_VERSION', version);
});
}
get values() {
return this._values;
}
updateDisplayName(name: string): void {
this._values = { ...this._values, APP_NAME: name } as const;
this._titleService.setTitle(this._values.APP_NAME || 'RedactManager');
}
}

View File

@ -1,17 +1,17 @@
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { ConfigService } from '@services/config.service';
import { BASE_HREF } from '../tokens';
@Injectable()
export class ApiPathInterceptor implements HttpInterceptor {
constructor(@Inject(BASE_HREF) private readonly _baseHref: string, private readonly _appConfigService: AppConfigService) {}
constructor(@Inject(BASE_HREF) private readonly _baseHref: string, private readonly _configService: ConfigService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
if (!req.url.startsWith('/assets')) {
const updatedRequest = req.clone({
url: this._appConfigService.getConfig(AppConfigKey.API_URL) + req.url
url: this._configService.values.API_URL + req.url
});
return next.handle(updatedRequest);
} else {

View File

@ -0,0 +1,27 @@
import { GeneralSettingsControllerService } from '@redaction/red-ui-http';
import { catchError, filter, mergeMap, take, tap } from 'rxjs/operators';
import { ConfigService } from '@services/config.service';
import { Title } from '@angular/platform-browser';
import { of } from 'rxjs';
import { KeycloakEventType, KeycloakService } from 'keycloak-angular';
export function configurationInitializer(
keycloakService: KeycloakService,
title: Title,
configService: ConfigService,
generalSettingsControllerService: GeneralSettingsControllerService
) {
return () =>
keycloakService.keycloakEvents$
.pipe(
filter(event => event.type === KeycloakEventType.OnReady),
mergeMap(() => generalSettingsControllerService.getGeneralConfigurations()),
tap(configuration => configService.updateDisplayName(configuration.displayName)),
catchError(() => {
title.setTitle('RedactManager');
return of({});
}),
take(1)
)
.toPromise();
}

View File

@ -1,14 +1,14 @@
import { hexToRgb } from './functions';
import { environment } from '@environments/environment';
import { PDFNet } from '@pdftron/webviewer';
import PDFDoc = PDFNet.PDFDoc;
import { Core } from '@pdftron/webviewer';
import PDFDoc = Core.PDFNet.PDFDoc;
export async function clearStamps(document: PDFDoc, PdfNet: any, pages: number[]) {
await PdfNet.runWithCleanup(
export async function clearStamps(document: PDFDoc, pdfNet: any, pages: number[]) {
await pdfNet.runWithCleanup(
async () => {
await document.lock();
const pageSet = await createPageSet(PdfNet, pages);
await PdfNet.Stamper.deleteStamps(document, pageSet);
const pageSet = await createPageSet(pdfNet, pages);
await pdfNet.Stamper.deleteStamps(document, pageSet);
},
environment.licenseKey ? atob(environment.licenseKey) : null
);
@ -16,7 +16,7 @@ export async function clearStamps(document: PDFDoc, PdfNet: any, pages: number[]
export async function stampPDFPage(
document: PDFDoc,
PdfNet: any,
pdfNet: any,
text: string,
fontSize: number,
fontType: string,
@ -25,17 +25,17 @@ export async function stampPDFPage(
color: string,
pages: number[]
) {
await PdfNet.runWithCleanup(
await pdfNet.runWithCleanup(
async () => {
await document.lock();
const pageSet = await createPageSet(PdfNet, pages);
await PdfNet.Stamper.deleteStamps(document, pageSet);
const pageSet = await createPageSet(pdfNet, pages);
await pdfNet.Stamper.deleteStamps(document, pageSet);
const rgbColor = hexToRgb(color);
const stamper = await PdfNet.Stamper.create(3, fontSize, 0);
await stamper.setFontColor(await PdfNet.ColorPt.init(rgbColor.r / 255, rgbColor.g / 255, rgbColor.b / 255));
const stamper = await pdfNet.Stamper.create(3, fontSize, 0);
await stamper.setFontColor(await pdfNet.ColorPt.init(rgbColor.r / 255, rgbColor.g / 255, rgbColor.b / 255));
await stamper.setOpacity(opacity / 100);
switch (orientation) {
@ -51,7 +51,7 @@ export async function stampPDFPage(
await stamper.setRotation(-45);
}
const font = await PdfNet.Font.createAndEmbed(document, convertFont(fontType));
const font = await pdfNet.Font.createAndEmbed(document, convertFont(fontType));
await stamper.setFont(font);
await stamper.setTextAlignment(0);
await stamper.stampText(document, text, pageSet);
@ -60,8 +60,8 @@ export async function stampPDFPage(
);
}
async function createPageSet(PdfNet: any, pages: number[]) {
const pageSet = await PdfNet.PageSet.create();
async function createPageSet(pdfNet: any, pages: number[]) {
const pageSet = await pdfNet.PageSet.create();
for (const page of pages) {
if (page > 0) {
await pageSet.addPage(page);

View File

@ -1,23 +0,0 @@
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ErrorService } from '@iqser/common-ui';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
@Injectable()
export class ServerErrorInterceptor implements HttpInterceptor {
constructor(private readonly _errorService: ErrorService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
map((event: HttpEvent<any>) => event),
catchError((error: HttpErrorResponse) => {
if (error.status >= 500) {
// || error.status === 0
this._errorService.set(error);
}
return throwError(error);
})
);
}
}

View File

@ -1,17 +1,23 @@
{
"OAUTH_URL": "https://demo.redactmanager.com/auth/realms/redaction",
"ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null,
"API_URL": "https://demo.redactmanager.com/redaction-gateway-v1",
"OAUTH_CLIENT_ID": "redaction",
"APP_NAME": "RedactManager",
"AUTO_READ_TIME": 1.5,
"BACKEND_APP_VERSION": "4.4.40",
"FRONTEND_APP_VERSION": "1.1",
"DELETE_RETENTION_HOURS": 96,
"EULA_URL": "EULA_URL",
"FRONTEND_APP_VERSION": "1.1",
"LICENSE_CUSTOMER": "Development License",
"LICENSE_EMAIL": "todo-license@email.com",
"LICENSE_START": "01-01-2021",
"LICENSE_END": "31-12-2021",
"LICENSE_PAGE_COUNT": 1000000,
"SELECTION_MODE": "structural",
"RECENT_PERIOD_IN_HOURS": 24,
"LICENSE_START": "01-01-2021",
"MAX_FILE_SIZE_MB": 100,
"DELETE_RETENTION_HOURS": 96
"MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null,
"OAUTH_URL": "https://demo.redactmanager.com/auth/realms/redaction",
"RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural"
}

View File

@ -865,7 +865,9 @@
"generic": "Action failed with code {status}"
},
"reload": "Reload",
"title": "Oops! Something went wrong..."
"title": "Oops! Something went wrong...",
"offline": "You're offline",
"close": "Close"
},
"exact-date": "{day} {month} {year} at {hour}:{minute}",
"file": "File",

View File

@ -2,7 +2,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": []
"allowSyntheticDefaultImports": true
},
"files": ["src/main.ts", "src/polyfills.ts"]
}

View File

@ -1,44 +1,52 @@
#!/bin/sh
OAUTH_CLIENT_ID="${OAUTH_CLIENT_ID:-gin-client}"
OAUTH_URL="${OAUTH_URL:-https://keycloak-dev.iqser.cloud/auth/realms/dev}"
API_URL="${API_URL:-}"
OAUTH_IDP_HINT="${OAUTH_IDP_HINT:-}"
ADMIN_CONTACT_NAME="${ADMIN_CONTACT_NAME:-}"
ADMIN_CONTACT_URL="${ADMIN_CONTACT_URL:-}"
API_URL="${API_URL:-}"
APP_NAME="${APP_NAME:-}"
AUTO_READ_TIME="${AUTO_READ_TIME:-1.5}"
SELECTION_MODE="${SELECTION_MODE:-structural}"
MAX_FILE_SIZE_MB="${MAX_FILE_SIZE_MB:-50}"
DELETE_RETENTION_HOURS="${DELETE_RETENTION_HOURS:-96}"
RECENT_PERIOD_IN_HOURS="${RECENT_PERIOD_IN_HOURS:-24}"
BACKEND_APP_VERSION="${BACKEND_APP_VERSION:-4.7.0}"
DELETE_RETENTION_HOURS="${DELETE_RETENTION_HOURS:-96}"
EULA_URL="${EULA_URL:-}"
FRONTEND_APP_VERSION="${FRONTEND_APP_VERSION:-}"
LICENSE_START="${LICENSE_START:-01-01-2021}"
LICENSE_END="${LICENSE_END:-31-12-2021}"
LICENSE_PAGE_COUNT="${LICENSE_PAGE_COUNT:-1000000}"
LICENSE_CUSTOMER="${LICENSE_CUSTOMER:-Developement License}"
LICENSE_EMAIL="${LICENSE_EMAIL:-license@iqser.com}"
LICENSE_END="${LICENSE_END:-31-12-2021}"
LICENSE_PAGE_COUNT="${LICENSE_PAGE_COUNT:-1000000}"
LICENSE_START="${LICENSE_START:-01-01-2021}"
MAX_FILE_SIZE_MB="${MAX_FILE_SIZE_MB:-50}"
MAX_RETRIES_ON_SERVER_ERROR="${MAX_RETRIES_ON_SERVER_ERROR:-3}"
OAUTH_CLIENT_ID="${OAUTH_CLIENT_ID:-gin-client}"
OAUTH_IDP_HINT="${OAUTH_IDP_HINT:-}"
OAUTH_URL="${OAUTH_URL:-https://keycloak-dev.iqser.cloud/auth/realms/dev}"
RECENT_PERIOD_IN_HOURS="${RECENT_PERIOD_IN_HOURS:-24}"
SELECTION_MODE="${SELECTION_MODE:-structural}"
echo '{
"OAUTH_CLIENT_ID":"'"$OAUTH_CLIENT_ID"'",
"OAUTH_URL":"'"$OAUTH_URL"'",
"OAUTH_IDP_HINT":"'"$OAUTH_IDP_HINT"'",
"BACKEND_APP_VERSION":"'"$BACKEND_APP_VERSION"'",
"ADMIN_CONTACT_NAME":"'"$ADMIN_CONTACT_NAME"'",
"ADMIN_CONTACT_URL":"'"$ADMIN_CONTACT_URL"'",
"LICENSE_START":"'"$LICENSE_START"'",
"LICENSE_END":"'"$LICENSE_END"'",
"LICENSE_PAGE_COUNT":'"$LICENSE_PAGE_COUNT"',
"API_URL":"'"$API_URL"'"
"APP_NAME":"'"$APP_NAME"'"
"AUTO_READ_TIME":'"$AUTO_READ_TIME"',
"BACKEND_APP_VERSION":"'"$BACKEND_APP_VERSION"'",
"DELETE_RETENTION_HOURS":'"$DELETE_RETENTION_HOURS"',
"EULA_URL":'"$EULA_URL"',
"FRONTEND_APP_VERSION":'"$FRONTEND_APP_VERSION"',
"LICENSE_CUSTOMER":"'"$LICENSE_CUSTOMER"'",
"LICENSE_EMAIL":"'"$LICENSE_EMAIL"'",
"AUTO_READ_TIME":'"$AUTO_READ_TIME"',
"SELECTION_MODE":"'"$SELECTION_MODE"'",
"LICENSE_END":"'"$LICENSE_END"'",
"LICENSE_PAGE_COUNT":'"$LICENSE_PAGE_COUNT"',
"LICENSE_START":"'"$LICENSE_START"'",
"MAX_FILE_SIZE_MB":"'"$MAX_FILE_SIZE_MB"'",
"MAX_RETRIES_ON_SERVER_ERROR":"'"$MAX_RETRIES_ON_SERVER_ERROR"'",
"OAUTH_CLIENT_ID":"'"$OAUTH_CLIENT_ID"'",
"OAUTH_IDP_HINT":"'"$OAUTH_IDP_HINT"'",
"OAUTH_URL":"'"$OAUTH_URL"'",
"RECENT_PERIOD_IN_HOURS":'"$RECENT_PERIOD_IN_HOURS"',
"DELETE_RETENTION_HOURS":'"$DELETE_RETENTION_HOURS"',
"API_URL":"'"$API_URL"'"
"SELECTION_MODE":"'"$SELECTION_MODE"'",
}' > /usr/share/nginx/html/ui/assets/config/config.json
echo 'Env variables: '

View File

@ -1,3 +1,3 @@
module.exports = {
projects: ['<rootDir>/apps/red-ui', '<rootDir>/libs/red-ui-http', '<rootDir>/libs/red-cache', '<rootDir>/libs/common-ui']
};
const { getJestProjects } = require('@nrwl/jest');
module.exports = { projects: getJestProjects() };

@ -1 +1 @@
Subproject commit 6c0f123bd97148f8696038f63c9951c241b71990
Subproject commit 90287baf62e8a5cfbec742b6947352c56c255bdb

View File

@ -4,9 +4,7 @@ module.exports = {
globals: {
'ts-jest': {
stringifyContentPathRegex: '\\.(html|svg)$',
astTransformers: {
before: ['jest-preset-angular/build/InlineFilesTransformer', 'jest-preset-angular/build/StripStylesTransformer']
},
tsconfig: '<rootDir>/tsconfig.spec.json'
}
},
@ -17,5 +15,6 @@ module.exports = {
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment'
]
],
transform: { '^.+\\.(ts|js|html)$': 'jest-preset-angular' }
};

View File

@ -4,9 +4,7 @@ module.exports = {
globals: {
'ts-jest': {
stringifyContentPathRegex: '\\.(html|svg)$',
astTransformers: {
before: ['jest-preset-angular/build/InlineFilesTransformer', 'jest-preset-angular/build/StripStylesTransformer']
},
tsconfig: '<rootDir>/tsconfig.spec.json'
}
},
@ -17,5 +15,6 @@ module.exports = {
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment'
]
],
transform: { '^.+\\.(ts|js|html)$': 'jest-preset-angular' }
};

18
nx.json
View File

@ -22,17 +22,25 @@
}
},
"projects": {
"red-ui": {
"tags": []
},
"red-ui-http": {
"common-ui": {
"tags": []
},
"red-cache": {
"tags": []
},
"common-ui": {
"red-ui": {
"tags": []
},
"red-ui-http": {
"tags": []
}
},
"targetDependencies": {
"build": [
{
"target": "build",
"projects": "dependencies"
}
]
}
}

View File

@ -26,9 +26,10 @@
"lint": "nx workspace-lint && nx lint",
"lint-fix": "nx workspace-lint --fix && nx lint --fix",
"nx": "nx",
"start": "nx serve --base-href /ui/",
"start": "nx serve",
"test": "nx test",
"update": "nx migrate latest",
"migrate": "nx migrate --run-migrations",
"workspace-generator": "nx workspace-generator"
},
"husky": {
@ -37,88 +38,88 @@
}
},
"dependencies": {
"@angular/animations": "12.0.4",
"@angular/cdk": "~12.0.4",
"@angular/common": "12.0.4",
"@angular/compiler": "12.0.4",
"@angular/core": "12.0.4",
"@angular/forms": "12.0.4",
"@angular/material": "~12.0.4",
"@angular/material-moment-adapter": "^12.0.4",
"@angular/platform-browser": "12.0.4",
"@angular/platform-browser-dynamic": "12.0.4",
"@angular/router": "12.0.4",
"@angular/service-worker": "12.0.4",
"@angular/animations": "12.2.5",
"@angular/cdk": "~12.2.5",
"@angular/common": "12.2.5",
"@angular/compiler": "12.2.5",
"@angular/core": "12.2.5",
"@angular/forms": "12.2.5",
"@angular/material": "12.2.5",
"@angular/material-moment-adapter": "^12.2.5",
"@angular/platform-browser": "12.2.5",
"@angular/platform-browser-dynamic": "12.2.5",
"@angular/router": "12.2.5",
"@angular/service-worker": "12.2.5",
"@biesbjerg/ngx-translate-extract-marker": "^1.0.0",
"@materia-ui/ngx-monaco-editor": "^5.1.0",
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"@nrwl/angular": "12.3.6",
"@pdftron/webviewer": "7.3.3",
"@nrwl/angular": "12.9.0",
"@pdftron/webviewer": "8.1.0",
"@swimlane/ngx-charts": "^17.0.1",
"file-saver": "^2.0.5",
"jwt-decode": "^3.1.2",
"keycloak-angular": "^8.2.0",
"keycloak-js": "13.0.1",
"keycloak-angular": "^8.4.0",
"keycloak-js": "15.0.2",
"lodash": "^4.17.21",
"messageformat": "^2.3.0",
"moment": "^2.29.1",
"ngx-color-picker": "^11.0.0",
"ngx-toastr": "^14.0.0",
"ngx-toastr": "^14.1.3",
"ngx-translate-messageformat-compiler": "^4.10.0",
"papaparse": "^5.3.1",
"rxjs": "~6.6.7",
"sass": "^1.35.1",
"sass": "^1.39.2",
"scroll-into-view-if-needed": "^2.2.28",
"streamsaver": "^2.0.5",
"tslib": "^2.2.0",
"tslib": "^2.3.1",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "12.0.4",
"@angular-eslint/eslint-plugin": "12.1.0",
"@angular-eslint/eslint-plugin-template": "12.1.0",
"@angular-eslint/template-parser": "12.1.0",
"@angular/cli": "12.0.4",
"@angular/compiler-cli": "12.0.4",
"@angular/language-service": "12.0.4",
"@angular-devkit/build-angular": "12.2.5",
"@angular-eslint/eslint-plugin": "12.4.1",
"@angular-eslint/eslint-plugin-template": "12.4.1",
"@angular-eslint/template-parser": "12.4.1",
"@angular/cli": "12.2.5",
"@angular/compiler-cli": "12.2.5",
"@angular/language-service": "12.2.5",
"@biesbjerg/ngx-translate-extract": "^7.0.4",
"@nrwl/cli": "12.3.6",
"@nrwl/cypress": "12.3.6",
"@nrwl/eslint-plugin-nx": "12.3.6",
"@nrwl/jest": "12.3.6",
"@nrwl/linter": "12.3.6",
"@nrwl/tao": "12.3.6",
"@nrwl/workspace": "12.3.6",
"@nrwl/cli": "12.9.0",
"@nrwl/cypress": "12.9.0",
"@nrwl/eslint-plugin-nx": "12.9.0",
"@nrwl/jest": "12.9.0",
"@nrwl/linter": "12.9.0",
"@nrwl/tao": "12.9.0",
"@nrwl/workspace": "12.9.0",
"@types/cypress": "^1.1.3",
"@types/jest": "26.0.23",
"@types/jest": "27.0.1",
"@types/lodash": "^4.14.172",
"@types/node": "15.12.2",
"@typescript-eslint/eslint-plugin": "4.26.1",
"@typescript-eslint/parser": "4.26.1",
"@types/node": "16.9.1",
"@typescript-eslint/eslint-plugin": "4.31.0",
"@typescript-eslint/parser": "4.31.0",
"cypress": "^6.9.1",
"cypress-file-upload": "^5.0.7",
"cypress-file-upload": "^5.0.8",
"cypress-keycloak": "^1.7.0",
"cypress-keycloak-commands": "^1.2.0",
"cypress-localstorage-commands": "^1.4.5",
"cypress-localstorage-commands": "^1.5.0",
"dotenv": "10.0.0",
"eslint": "7.28.0",
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint": "7.32.0",
"eslint-config-airbnb-typescript": "^14.0.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-import": "2.24.2",
"google-translate-api-browser": "^1.1.71",
"husky": "4.3.8",
"jest": "27.0.4",
"jest-preset-angular": "9.0.3",
"ng-packagr": "12.0.5",
"prettier": "2.3.1",
"pretty-quick": "^3.1.0",
"jest": "27.1.1",
"jest-preset-angular": "9.0.7",
"ng-packagr": "12.2.1",
"prettier": "2.4.0",
"pretty-quick": "^3.1.1",
"superagent": "^6.1.0",
"superagent-promise": "^1.1.0",
"ts-jest": "27.0.3",
"ts-node": "10.0.0",
"typescript": "4.2.4",
"ts-jest": "27.0.5",
"ts-node": "10.2.1",
"typescript": "4.3.5",
"webpack": "^4.18.1"
}
}

View File

@ -17,20 +17,19 @@
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {
"@redaction/red-ui-http": ["libs/red-ui-http/src/index.ts"],
"@redaction/red-cache": ["libs/red-cache/src/index.ts"],
"@services/*": ["apps/red-ui/src/app/services/*"],
"@components/*": ["apps/red-ui/src/app/components/*"],
"@environments/*": ["apps/red-ui/src/environments/*"],
"@guards/*": ["apps/red-ui/src/app/guards/*"],
"@i18n/*": ["apps/red-ui/src/app/i18n/*"],
"@state/*": ["apps/red-ui/src/app/state/*"],
"@utils/*": ["apps/red-ui/src/app/utils/*"],
"@iqser/common-ui": ["libs/common-ui/src/index.ts"],
"@models/*": ["apps/red-ui/src/app/models/*"],
"@environments/*": ["apps/red-ui/src/environments/*"],
"@redaction/red-cache": ["libs/red-cache/src/index.ts"],
"@redaction/red-ui-http": ["libs/red-ui-http/src/index.ts"],
"@services/*": ["apps/red-ui/src/app/services/*"],
"@shared/*": ["apps/red-ui/src/app/modules/shared/*"],
"@app-config/*": ["apps/red-ui/src/app/modules/app-config/*"],
"@state/*": ["apps/red-ui/src/app/state/*"],
"@upload-download/*": ["apps/red-ui/src/app/modules/upload-download/*"],
"@iqser/common-ui": ["libs/common-ui/src/index.ts"]
"@utils/*": ["apps/red-ui/src/app/utils/*"]
}
},
"exclude": ["node_modules", "tmp"],

4980
yarn.lock

File diff suppressed because it is too large Load Diff