Merge branch 'master' into workflow
This commit is contained in:
commit
aeb804b591
2
.gitignore
vendored
2
.gitignore
vendored
@ -41,3 +41,5 @@ Thumbs.db
|
||||
version.properties
|
||||
|
||||
paligo-styles/style.css*
|
||||
|
||||
migrations.json
|
||||
|
||||
112
angular.json
112
angular.json
@ -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",
|
||||
{
|
||||
@ -57,7 +109,10 @@
|
||||
},
|
||||
"apps/red-ui/src/manifest.webmanifest"
|
||||
],
|
||||
"styles": ["apps/red-ui/src/styles.scss", "libs/common-ui/src/assets/styles/common.scss"],
|
||||
"styles": ["apps/red-ui/src/styles.scss", "libs/common-ui/src/assets/styles/common-styles.scss"],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": ["./apps/red-ui/src/assets/styles", "./libs/common-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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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' }
|
||||
};
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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) {}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@import '../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.dev-mode {
|
||||
background-color: $primary;
|
||||
color: $white;
|
||||
background-color: variables.$primary;
|
||||
color: variables.$white;
|
||||
font-size: 22px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import '../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
color: $primary;
|
||||
color: variables.$primary;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.mt-2 {
|
||||
margin-top: 2px;
|
||||
@ -35,7 +35,7 @@
|
||||
white-space: normal;
|
||||
|
||||
a {
|
||||
color: $accent;
|
||||
color: variables.$accent;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
@ -45,17 +45,17 @@
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: $grey-4;
|
||||
background-color: variables.$grey-4;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-6;
|
||||
background-color: variables.$grey-6;
|
||||
|
||||
.dot {
|
||||
background-color: $grey-5;
|
||||
background-color: variables.$grey-5;
|
||||
}
|
||||
|
||||
a {
|
||||
@ -64,10 +64,10 @@
|
||||
}
|
||||
|
||||
&.unread {
|
||||
background-color: rgba($primary, 0.1);
|
||||
background-color: rgba(variables.$primary, 0.1);
|
||||
|
||||
.dot {
|
||||
background-color: $primary;
|
||||
background-color: variables.$primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.spotlight-row {
|
||||
width: 300px;
|
||||
@ -9,13 +9,13 @@
|
||||
font-size: 13px;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: $accent;
|
||||
background-color: $white;
|
||||
color: variables.$accent;
|
||||
background-color: variables.$white;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
border-radius: 4px;
|
||||
background-color: $grey-2;
|
||||
background-color: variables.$grey-2;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
|
||||
@ -1 +0,0 @@
|
||||
@import '../../../assets/styles/variables';
|
||||
@ -1,10 +1,10 @@
|
||||
@import '../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.content-container {
|
||||
background-color: $grey-2;
|
||||
background-color: variables.$grey-2;
|
||||
justify-content: center;
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
@ -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'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -57,11 +57,10 @@ export class AnnotationWrapper {
|
||||
|
||||
isChangeLogEntry?: boolean;
|
||||
changeLogType?: 'ADDED' | 'REMOVED';
|
||||
engines?: string[];
|
||||
|
||||
private _origin: RedactionLogEntryWrapper;
|
||||
|
||||
constructor() {}
|
||||
|
||||
get isChangeLogRemoved() {
|
||||
return this.changeLogType === 'REMOVED';
|
||||
}
|
||||
@ -220,6 +219,7 @@ export class AnnotationWrapper {
|
||||
annotationWrapper.legalBasisValue = redactionLogEntry.legalBasis;
|
||||
annotationWrapper.comments = redactionLogEntry.comments || [];
|
||||
annotationWrapper.manual = redactionLogEntry.manual;
|
||||
annotationWrapper.engines = redactionLogEntry.engines;
|
||||
|
||||
this._createContent(annotationWrapper, redactionLogEntry);
|
||||
this._setSuperType(annotationWrapper, redactionLogEntry);
|
||||
|
||||
@ -35,4 +35,5 @@ export interface RedactionLogEntryWrapper {
|
||||
|
||||
recategorizationType?: string;
|
||||
legalBasisChangeValue?: string;
|
||||
engines?: string[];
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
|
||||
.first-row {
|
||||
display: flex;
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<div [translateParams]="{ userName: userName }" [translate]="'reset-password-dialog.header'" class="dialog-header heading-l"></div>
|
||||
<div [translateParams]="{ userName: user | name }" [translate]="'reset-password-dialog.header'" class="dialog-header heading-l"></div>
|
||||
|
||||
<form (submit)="save()" [formGroup]="passwordForm">
|
||||
<div class="dialog-content">
|
||||
|
||||
@ -23,10 +23,6 @@ export class ResetPasswordComponent {
|
||||
private readonly _loadingService: LoadingService
|
||||
) {}
|
||||
|
||||
get userName() {
|
||||
return this._userService.getNameForId(this.user.id);
|
||||
}
|
||||
|
||||
async save() {
|
||||
this._loadingService.start();
|
||||
await this._userControllerService
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.dialog-header {
|
||||
color: $primary;
|
||||
color: variables.$primary;
|
||||
}
|
||||
|
||||
.heading {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.dialog-header {
|
||||
color: $primary;
|
||||
color: variables.$primary;
|
||||
}
|
||||
|
||||
.heading {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
:host ::ng-deep iqser-table {
|
||||
iqser-table-header {
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
.header-item {
|
||||
box-shadow: none;
|
||||
border-top: 1px solid $separator;
|
||||
border-top: 1px solid variables.$separator;
|
||||
|
||||
.all-caps-label {
|
||||
margin-right: 10px;
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
.separator {
|
||||
margin-left: 14px;
|
||||
background-color: $separator;
|
||||
background-color: variables.$separator;
|
||||
width: 1px;
|
||||
height: 30px;
|
||||
margin-right: 16px;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.sub-header {
|
||||
display: flex;
|
||||
@ -13,7 +13,7 @@
|
||||
padding-left: 32px;
|
||||
min-width: 376px;
|
||||
box-sizing: border-box;
|
||||
border-right: 1px solid $separator;
|
||||
border-right: 1px solid variables.$separator;
|
||||
|
||||
.info {
|
||||
margin-bottom: 8px;
|
||||
@ -55,9 +55,9 @@
|
||||
.csv-part-header {
|
||||
height: 50px;
|
||||
box-sizing: border-box;
|
||||
background: $white;
|
||||
border-top: 1px solid $separator;
|
||||
border-bottom: 1px solid $separator;
|
||||
background: variables.$white;
|
||||
border-top: 1px solid variables.$separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@ -83,14 +83,14 @@
|
||||
}
|
||||
|
||||
.search-input-container {
|
||||
background-color: $white;
|
||||
border-bottom: 1px solid $separator;
|
||||
background-color: variables.$white;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.csv-part-content {
|
||||
overflow: auto;
|
||||
@include no-scroll-bar;
|
||||
@include common-mixins.no-scroll-bar;
|
||||
height: calc(100% - 49px);
|
||||
font-size: 12px;
|
||||
|
||||
@ -101,13 +101,13 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
color: $grey-7;
|
||||
color: variables.$grey-7;
|
||||
line-height: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
> *:not(.no-column-data) {
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
display: flex;
|
||||
padding: 7px 16px;
|
||||
align-items: center;
|
||||
@ -117,14 +117,14 @@
|
||||
> .left {
|
||||
width: 375px;
|
||||
min-width: 375px;
|
||||
background: $grey-2;
|
||||
background: variables.$grey-2;
|
||||
|
||||
.csv-header-pill-content {
|
||||
overflow: auto;
|
||||
padding: 7px 0;
|
||||
background: $grey-2;
|
||||
background: variables.$grey-2;
|
||||
height: calc(100% - 64px);
|
||||
@include no-scroll-bar;
|
||||
@include common-mixins.no-scroll-bar;
|
||||
|
||||
&.search-open {
|
||||
height: calc(100% - 58px - 51px);
|
||||
@ -137,7 +137,7 @@
|
||||
min-height: 32px;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
background: $white;
|
||||
background: variables.$white;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -153,26 +153,26 @@
|
||||
}
|
||||
|
||||
.sample {
|
||||
@include line-clamp(1);
|
||||
@include common-mixins.line-clamp(1);
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: $primary;
|
||||
color: $white;
|
||||
background-color: variables.$primary;
|
||||
color: variables.$white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
border-right: 1px solid $separator;
|
||||
border-right: 1px solid variables.$separator;
|
||||
}
|
||||
|
||||
> .center {
|
||||
width: 150px;
|
||||
min-width: 150px;
|
||||
background: $grey-2;
|
||||
border-right: 1px solid $separator;
|
||||
background: variables.$grey-2;
|
||||
border-right: 1px solid variables.$separator;
|
||||
|
||||
&:not(.collapsed) iqser-circle-button {
|
||||
margin-right: -8px;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
|
||||
&.center {
|
||||
@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
&.label span {
|
||||
@include line-clamp(1);
|
||||
@include common-mixins.line-clamp(1);
|
||||
}
|
||||
|
||||
&.read-only mat-icon {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.content-container {
|
||||
background-color: $grey-2;
|
||||
background-color: variables.$grey-2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
}
|
||||
|
||||
.inline-input-group {
|
||||
background-color: rgba($grey-6, 0.8);
|
||||
background-color: rgba(variables.$grey-6, 0.8);
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
border-radius: 4px;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'common-mixins';
|
||||
@use 'variables';
|
||||
|
||||
.content-container {
|
||||
overflow: auto;
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
&:hover {
|
||||
> div {
|
||||
background-color: $grey-2;
|
||||
background-color: variables.$grey-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,7 +37,7 @@
|
||||
grid-column: span 2;
|
||||
padding: 20px 20px 8px;
|
||||
margin-bottom: 8px;
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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';
|
||||
@ -29,10 +29,8 @@ export class LicenseInformationScreenComponent implements OnInit {
|
||||
unlicensedInfo: LicenseReport = {};
|
||||
totalLicensedNumberOfPages = 0;
|
||||
analysisPercentageOfLicense = 100;
|
||||
barChart: any[] = [];
|
||||
barChart: any[];
|
||||
lineChartSeries: any[] = [];
|
||||
yAxisLabel = this._translateService.instant('license-info-screen.chart.pages-per-month');
|
||||
yAxisLabelRight = this._translateService.instant('license-info-screen.chart.total-pages');
|
||||
lineChartScheme = {
|
||||
selectable: true,
|
||||
group: 'Ordinal',
|
||||
@ -45,8 +43,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 +58,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 +91,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 +104,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) {
|
||||
@ -151,6 +149,7 @@ export class LicenseInformationScreenComponent implements OnInit {
|
||||
m = startMonth;
|
||||
y = startYear;
|
||||
let cumulativePages = 0;
|
||||
this.barChart = [];
|
||||
for (const report of reports) {
|
||||
cumulativePages += report.numberOfAnalyzedPages;
|
||||
this.barChart.push({
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.content-container,
|
||||
.right-container {
|
||||
flex: 1;
|
||||
padding: 30px;
|
||||
overflow: auto;
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
}
|
||||
|
||||
.right-container {
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
.template {
|
||||
padding: 8px 10px;
|
||||
background-color: $grey-6;
|
||||
background-color: variables.$grey-6;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s;
|
||||
position: relative;
|
||||
@ -32,7 +32,7 @@
|
||||
|
||||
.name {
|
||||
max-width: calc(100% - 100px);
|
||||
@include line-clamp(1);
|
||||
@include common-mixins.line-clamp(1);
|
||||
}
|
||||
|
||||
.actions {
|
||||
@ -48,7 +48,7 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-4;
|
||||
background-color: variables.$grey-4;
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
@ -81,8 +81,8 @@
|
||||
grid-template-columns: 1fr 2fr;
|
||||
|
||||
.all-caps-label {
|
||||
border-top: 1px solid $separator;
|
||||
border-bottom: 1px solid $separator;
|
||||
border-top: 1px solid variables.$separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
padding: 8px 32px;
|
||||
|
||||
&:nth-child(2) {
|
||||
@ -93,7 +93,7 @@
|
||||
.placeholder,
|
||||
.description {
|
||||
padding: 16px 16px;
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.content-container {
|
||||
order: 1;
|
||||
@ -15,7 +15,7 @@
|
||||
min-width: 353px;
|
||||
padding: 24px;
|
||||
border-left: none;
|
||||
border-right: 1px solid $separator;
|
||||
border-right: 1px solid variables.$separator;
|
||||
|
||||
&.has-scrollbar:hover {
|
||||
padding-right: 13px;
|
||||
@ -32,8 +32,8 @@
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 8px;
|
||||
background-color: $grey-6;
|
||||
color: $grey-7;
|
||||
background-color: variables.$grey-6;
|
||||
color: variables.$grey-7;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
@ -46,7 +46,7 @@
|
||||
}
|
||||
|
||||
&:not(.disabled):not(.active):hover {
|
||||
background-color: darken($grey-6, 2);
|
||||
background-color: darken(variables.$grey-6, 2);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
@ -54,8 +54,8 @@
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $primary;
|
||||
color: $white;
|
||||
background-color: variables.$primary;
|
||||
color: variables.$white;
|
||||
}
|
||||
|
||||
&.times-new-roman {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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 {}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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({
|
||||
@ -10,19 +10,20 @@ import { BASE_HREF } from '../../tokens';
|
||||
})
|
||||
export class AuthGuard extends KeycloakAuthGuard {
|
||||
constructor(
|
||||
@Inject(BASE_HREF) private readonly _baseHref: string,
|
||||
protected readonly _router: Router,
|
||||
private readonly _userService: UserService,
|
||||
protected readonly _keycloak: KeycloakService,
|
||||
private readonly _appConfigService: AppConfigService,
|
||||
private readonly _userService: UserService
|
||||
private readonly _configService: ConfigService,
|
||||
@Inject(BASE_HREF) private readonly _baseHref: string
|
||||
) {
|
||||
super(_router, _keycloak);
|
||||
}
|
||||
|
||||
async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||
if (!this.authenticated) {
|
||||
const kcIdpHint = route.queryParamMap.get('kc_idp_hint');
|
||||
await this._keycloak.login({
|
||||
idpHint: this._appConfigService.getConfig(AppConfigKey.OAUTH_IDP_HINT, null),
|
||||
idpHint: kcIdpHint ?? this._configService.values.OAUTH_IDP_HINT,
|
||||
redirectUri: window.location.origin + this._baseHref + state.url
|
||||
});
|
||||
return false;
|
||||
|
||||
@ -1,59 +1,50 @@
|
||||
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';
|
||||
import { environment } from '@environments/environment';
|
||||
|
||||
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: 'login-required',
|
||||
silentCheckSsoRedirectUri: environment.production
|
||||
? window.location.origin + baseUrl + '/assets/oauth/silent-refresh.html'
|
||||
: null,
|
||||
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]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
|
||||
export const APP_BOOTSTRAPPED = new ReplaySubject<boolean>();
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.annotation-actions {
|
||||
display: none;
|
||||
@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
.confirm.active {
|
||||
background-color: $grey-2;
|
||||
background-color: variables.$grey-2;
|
||||
}
|
||||
|
||||
> *:not(:last-child) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -177,7 +177,22 @@ export class DossierOverviewBulkActionsComponent {
|
||||
}
|
||||
|
||||
approveDocuments() {
|
||||
this._performBulkAction(this._fileActionService.setFileApproved(this.selectedFiles));
|
||||
const foundUpdatedFile = this.selectedFiles.find(file => file.hasUpdates);
|
||||
if (foundUpdatedFile) {
|
||||
this._dialogService.openDialog(
|
||||
'confirm',
|
||||
null,
|
||||
new ConfirmationDialogInput({
|
||||
title: _('confirmation-dialog.approve-multiple-files.title'),
|
||||
question: _('confirmation-dialog.approve-multiple-files.question')
|
||||
}),
|
||||
() => {
|
||||
this._performBulkAction(this._fileActionService.setFileApproved(this.selectedFiles));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this._performBulkAction(this._fileActionService.setFileApproved(this.selectedFiles));
|
||||
}
|
||||
}
|
||||
|
||||
assignToMe() {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
<div *ngFor="let comment of annotation.comments" class="comment">
|
||||
<div class="comment-details-wrapper">
|
||||
<div [matTooltipPosition]="'above'" [matTooltip]="comment.date | date: 'exactDate'" class="small-label">
|
||||
<b> {{ getOwnerName(comment) }} </b>
|
||||
<strong> {{ comment.user | name }} </strong>
|
||||
{{ comment.date | date: 'sophisticatedDate' }}
|
||||
</div>
|
||||
|
||||
<div class="comment-actions">
|
||||
<iqser-circle-button
|
||||
(action)="deleteComment(comment)"
|
||||
@ -15,6 +16,7 @@
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>{{ comment.text }}</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -52,8 +52,4 @@ export class CommentsComponent {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getOwnerName(comment: Comment): string {
|
||||
return this._userService.getNameForId(comment.user);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
@ -13,7 +13,7 @@
|
||||
.right-content {
|
||||
flex-direction: column;
|
||||
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
@ -42,7 +42,7 @@
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import '../../../../../assets/styles/red-components';
|
||||
@import 'libs/common-ui/src/assets/styles/texts';
|
||||
@use 'variables';
|
||||
@use 'red-components';
|
||||
@use 'common-texts';
|
||||
|
||||
:host {
|
||||
@extend .stats-subtitle;
|
||||
@ -22,7 +22,7 @@
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-6;
|
||||
background-color: variables.$grey-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.header-wrapper {
|
||||
display: flex;
|
||||
@ -29,11 +29,11 @@
|
||||
padding: 3px 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-6;
|
||||
background-color: variables.$grey-6;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: rgba($primary, 0.1);
|
||||
background-color: rgba(variables.$primary, 0.1);
|
||||
}
|
||||
|
||||
&:not(:last-of-type) {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
|
||||
:host {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<ng-container *ngTemplateOutlet="actions"></ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #actions>
|
||||
<ng-template #actions redactionLongPress (longPress)="forceReanalysisAction($event)">
|
||||
<div *ngIf="fileStatus" class="file-actions">
|
||||
<iqser-circle-button
|
||||
(action)="openDocument()"
|
||||
@ -145,7 +145,6 @@
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:refresh"
|
||||
></iqser-circle-button>
|
||||
|
||||
<!-- exclude from redaction -->
|
||||
<div class="iqser-input-group">
|
||||
<mat-slide-toggle
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'common-mixins';
|
||||
|
||||
.file-actions {
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
@include no-scroll-bar;
|
||||
@include common-mixins.no-scroll-bar;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
|
||||
@ -10,6 +10,8 @@ import { FileManagementControllerService, FileStatus } from '@redaction/red-ui-h
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { UserPreferenceService } from '../../../../services/user-preference.service';
|
||||
import { LongPressEvent } from '../../../shared/directives/long-press.directive';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-file-actions',
|
||||
@ -55,7 +57,8 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _toaster: Toaster
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _userPreferenceService: UserPreferenceService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@ -152,8 +155,10 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
});
|
||||
}
|
||||
|
||||
reanalyseFile($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
reanalyseFile($event?: MouseEvent) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
this.addSubscription = this._fileActionService.reanalyseFile(this.fileStatus).subscribe(() => {
|
||||
this.reloadDossiers('reanalyse');
|
||||
});
|
||||
@ -172,9 +177,21 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
|
||||
setFileApproved($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this.addSubscription = this._fileActionService.setFileApproved(this.fileStatus).subscribe(() => {
|
||||
this.reloadDossiers('set-approved');
|
||||
});
|
||||
if (this.fileStatus.hasUpdates) {
|
||||
this._dialogService.openDialog(
|
||||
'confirm',
|
||||
$event,
|
||||
new ConfirmationDialogInput({
|
||||
title: _('confirmation-dialog.approve-file.title'),
|
||||
question: _('confirmation-dialog.approve-file.question')
|
||||
}),
|
||||
() => {
|
||||
this._setFileApproved();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this._setFileApproved();
|
||||
}
|
||||
}
|
||||
|
||||
ocrFile($event: MouseEvent) {
|
||||
@ -212,6 +229,18 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
|
||||
}
|
||||
}
|
||||
|
||||
forceReanalysisAction($event: LongPressEvent) {
|
||||
if (this._userPreferenceService.areDevFeaturesEnabled) {
|
||||
this.canReanalyse = $event.touchEnd ? this.permissionsService.canReanalyseFile(this.fileStatus) : true;
|
||||
}
|
||||
}
|
||||
|
||||
private _setFileApproved() {
|
||||
this.addSubscription = this._fileActionService.setFileApproved(this.fileStatus).subscribe(() => {
|
||||
this.reloadDossiers('set-approved');
|
||||
});
|
||||
}
|
||||
|
||||
private _setup() {
|
||||
this.statusBarConfig = [{ color: this.fileStatus.status, length: 1 }];
|
||||
this.tooltipPosition = this.isFilePreview ? 'below' : 'above';
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
<ng-container *ngIf="hasEnginesToShow">
|
||||
<div cdkOverlayOrigin #trigger="cdkOverlayOrigin" class="chip" (mouseover)="isPopoverOpen = true" (mouseout)="isPopoverOpen = false">
|
||||
<ng-container *ngFor="let engine of engines">
|
||||
<mat-icon *ngIf="engine.show" [svgIcon]="engine.icon"></mat-icon>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayOffsetY]="-8"
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
[cdkConnectedOverlayOpen]="isPopoverOpen"
|
||||
>
|
||||
<div class="popover">
|
||||
<ng-container *ngFor="let engine of engines">
|
||||
<div *ngIf="engine.show" class="flex-align-items-center">
|
||||
<mat-icon [svgIcon]="engine.icon"></mat-icon>
|
||||
<span>{{ engine.description }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
@ -0,0 +1,51 @@
|
||||
@use 'variables';
|
||||
|
||||
.popover {
|
||||
width: 260px;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
background-color: variables.$grey-1;
|
||||
color: variables.$white;
|
||||
|
||||
mat-icon {
|
||||
color: variables.$white;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
padding-left: 8px;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.chip {
|
||||
height: 24px;
|
||||
|
||||
&:hover {
|
||||
background-color: variables.$grey-6;
|
||||
border-radius: 12px;
|
||||
|
||||
mat-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
opacity: 50%;
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
width: 10px;
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { OnChange } from '@iqser/common-ui';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
interface Engine {
|
||||
readonly icon: string;
|
||||
readonly description: string;
|
||||
readonly show: boolean;
|
||||
}
|
||||
|
||||
type Engines = readonly Engine[];
|
||||
|
||||
const Engines = {
|
||||
DICTIONARY: 'DICTIONARY',
|
||||
NER: 'NER',
|
||||
RULE: 'RULE'
|
||||
} as const;
|
||||
|
||||
type EngineName = keyof typeof Engines;
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-annotation-source',
|
||||
templateUrl: './annotation-source.component.html',
|
||||
styleUrls: ['./annotation-source.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AnnotationSourceComponent {
|
||||
@Input()
|
||||
@OnChange<AnnotationWrapper, AnnotationSourceComponent>('updateEngines')
|
||||
annotation: AnnotationWrapper;
|
||||
|
||||
isPopoverOpen = false;
|
||||
engines: Engines;
|
||||
|
||||
constructor(private readonly _translateService: TranslateService) {}
|
||||
|
||||
get hasEnginesToShow(): boolean {
|
||||
return this.engines.length && this.engines.some(source => source.show);
|
||||
}
|
||||
|
||||
updateEngines(): void {
|
||||
this.engines = [
|
||||
{
|
||||
icon: 'red:dictionary',
|
||||
description: this._translateService.instant('annotation-engines.dictionary'),
|
||||
show: this._isBasedOn(Engines.DICTIONARY)
|
||||
},
|
||||
{
|
||||
icon: 'red:ai',
|
||||
description: this._translateService.instant('annotation-engines.ner'),
|
||||
show: this._isBasedOn(Engines.NER)
|
||||
},
|
||||
{
|
||||
icon: 'red:rule',
|
||||
description: this._translateService.instant('annotation-engines.rule', { rule: this.annotation.legalBasisValue }),
|
||||
show: this._isBasedOn(Engines.RULE)
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private _isBasedOn(engineName: EngineName) {
|
||||
return !!this.annotation.engines?.includes(engineName);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
<div
|
||||
(click)="annotationClicked(annotation, $event)"
|
||||
*ngFor="let annotation of annotations"
|
||||
[attr.annotation-id]="annotation.id"
|
||||
[attr.annotation-page]="activeViewerPage"
|
||||
[class.active]="isSelected(annotation.annotationId)"
|
||||
[class.multi-select-active]="multiSelectActive"
|
||||
class="annotation-wrapper"
|
||||
>
|
||||
<div class="active-bar-marker"></div>
|
||||
|
||||
<div [class.removed]="annotation.isChangeLogRemoved" class="annotation">
|
||||
<div [matTooltip]="annotation.content" class="details" matTooltipPosition="above">
|
||||
<redaction-type-annotation-icon [annotation]="annotation | log"></redaction-type-annotation-icon>
|
||||
|
||||
<div class="flex-1">
|
||||
<div>
|
||||
<strong>{{ annotation.typeLabel | translate }}</strong>
|
||||
</div>
|
||||
<div *ngIf="annotation?.type !== 'manual'">
|
||||
<strong>
|
||||
<span>{{ annotation.descriptor | translate }}</span
|
||||
>: </strong
|
||||
>{{ annotation.type | humanize: false }}
|
||||
</div>
|
||||
<div *ngIf="annotation.shortContent && !annotation.isHint">
|
||||
<strong><span translate="content"></span>: </strong>{{ annotation.shortContent }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="active-icon-marker-container">
|
||||
<iqser-round-checkbox
|
||||
*ngIf="multiSelectActive && isSelected(annotation.annotationId)"
|
||||
[active]="true"
|
||||
></iqser-round-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions-wrapper">
|
||||
<div
|
||||
(click)="comments.toggleExpandComments($event)"
|
||||
[matTooltip]="'comments.comments' | translate: { count: annotation.comments?.length }"
|
||||
class="comments-counter"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<mat-icon svgIcon="red:comment"></mat-icon>
|
||||
{{ annotation.comments.length }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="!multiSelectActive" class="actions">
|
||||
<ng-container
|
||||
[ngTemplateOutletContext]="{ annotation: annotation }"
|
||||
[ngTemplateOutlet]="annotationActionsTemplate"
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<redaction-comments #comments [annotation]="annotation"></redaction-comments>
|
||||
</div>
|
||||
|
||||
<redaction-annotation-source [annotation]="annotation"></redaction-annotation-source>
|
||||
</div>
|
||||
@ -0,0 +1,96 @@
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.annotation-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
|
||||
.active-bar-marker {
|
||||
min-width: 4px;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.active-icon-marker-container {
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
&:not(.lower-height) .active-bar-marker {
|
||||
background-color: variables.$primary;
|
||||
}
|
||||
}
|
||||
|
||||
.annotation {
|
||||
padding: 10px 16px 8px 10px;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
&.removed {
|
||||
text-decoration: line-through;
|
||||
color: variables.$grey-7;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.actions-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 8px;
|
||||
min-height: 34px;
|
||||
padding-left: 18px;
|
||||
|
||||
.comments-counter {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
transition: background-color 0.2s;
|
||||
line-height: 13px;
|
||||
height: 24px;
|
||||
border-radius: 12px;
|
||||
|
||||
mat-icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: variables.$grey-4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redaction-type-annotation-icon {
|
||||
margin-top: 6px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: variables.$grey-8;
|
||||
|
||||
::ng-deep .annotation-actions {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redaction-annotation-source {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 8px;
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { IqserEventTarget } from '@iqser/common-ui';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-annotations-list',
|
||||
templateUrl: './annotations-list.component.html',
|
||||
styleUrls: ['./annotations-list.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AnnotationsListComponent {
|
||||
@Input() annotations: AnnotationWrapper[];
|
||||
@Input() selectedAnnotations: AnnotationWrapper[];
|
||||
@Input() annotationActionsTemplate: TemplateRef<unknown>;
|
||||
@Input() multiSelectActive = false;
|
||||
@Input() activeViewerPage: number;
|
||||
@Input() canMultiSelect = true;
|
||||
|
||||
@Output() readonly multiSelectActiveChange = new EventEmitter<boolean>();
|
||||
@Output() readonly pagesPanelActive = new EventEmitter<boolean>();
|
||||
@Output() readonly selectAnnotations = new EventEmitter<
|
||||
AnnotationWrapper[] | { annotations: AnnotationWrapper[]; multiSelect: boolean }
|
||||
>();
|
||||
@Output() readonly deselectAnnotations = new EventEmitter<AnnotationWrapper[]>();
|
||||
|
||||
annotationClicked(annotation: AnnotationWrapper, $event: MouseEvent): void {
|
||||
if (($event.target as IqserEventTarget).localName === 'input') {
|
||||
return;
|
||||
}
|
||||
this.pagesPanelActive.emit(false);
|
||||
if (this.isSelected(annotation.annotationId)) {
|
||||
this.deselectAnnotations.emit([annotation]);
|
||||
} else {
|
||||
if (this.canMultiSelect && ($event.ctrlKey || $event.metaKey) && this.selectedAnnotations.length > 0) {
|
||||
this.multiSelectActive = true;
|
||||
this.multiSelectActiveChange.emit(true);
|
||||
}
|
||||
this.selectAnnotations.emit({
|
||||
annotations: [annotation],
|
||||
multiSelect: this.multiSelectActive
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isSelected(annotationId: string): boolean {
|
||||
return !!this.selectedAnnotations?.find(a => a?.annotationId === annotationId);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,3 @@
|
||||
<!-- This is a hack to subscribe to an observable using async pipe instead of component class -->
|
||||
<ng-container *ngIf="displayedAnnotations$ | async"></ng-container>
|
||||
|
||||
<div *ngIf="!excludePages" class="right-title heading" translate="file-preview.tabs.annotations.label">
|
||||
<div>
|
||||
<div
|
||||
@ -150,8 +147,7 @@
|
||||
(click)="actionPerformed.emit('view-exclude-pages')"
|
||||
class="with-underline"
|
||||
translate="file-preview.excluded-from-redaction"
|
||||
>
|
||||
</a
|
||||
></a
|
||||
>.
|
||||
</ng-container>
|
||||
</iqser-empty-state>
|
||||
@ -174,62 +170,17 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div
|
||||
(click)="annotationClicked(annotation, $event)"
|
||||
*ngFor="let annotation of displayedAnnotations.get(activeViewerPage)"
|
||||
[attr.annotation-id]="annotation.id"
|
||||
[attr.annotation-page]="activeViewerPage"
|
||||
[class.active]="isSelected(annotation)"
|
||||
[class.multi-select-active]="multiSelectActive"
|
||||
class="annotation-wrapper"
|
||||
>
|
||||
<div class="active-bar-marker"></div>
|
||||
<div [class.removed]="annotation.isChangeLogRemoved" class="annotation">
|
||||
<div [matTooltip]="annotation.content" class="details" matTooltipPosition="above">
|
||||
<redaction-type-annotation-icon [annotation]="annotation"></redaction-type-annotation-icon>
|
||||
<div class="flex-1">
|
||||
<div>
|
||||
<strong>{{ annotation.typeLabel | translate }}</strong>
|
||||
</div>
|
||||
<div *ngIf="annotation?.type !== 'manual'">
|
||||
<strong>
|
||||
<span>{{ annotation.descriptor | translate }}</span
|
||||
>: </strong
|
||||
>{{ annotation.type | humanize: false }}
|
||||
</div>
|
||||
<div *ngIf="annotation.shortContent && !annotation.isHint">
|
||||
<strong><span translate="content"></span>: </strong>{{ annotation.shortContent }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="active-icon-marker-container">
|
||||
<iqser-round-checkbox
|
||||
*ngIf="multiSelectActive && isSelected(annotation)"
|
||||
[active]="true"
|
||||
></iqser-round-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions-wrapper">
|
||||
<div
|
||||
(click)="toggleExpandComments(annotation, $event)"
|
||||
[matTooltip]="'comments.comments' | translate: { count: annotation.comments?.length }"
|
||||
class="comments-counter"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<mat-icon svgIcon="red:comment"></mat-icon>
|
||||
{{ annotation.comments.length }}
|
||||
</div>
|
||||
<div *ngIf="!multiSelectActive" class="actions">
|
||||
<ng-container
|
||||
[ngTemplateOutletContext]="{ annotation: annotation }"
|
||||
[ngTemplateOutlet]="annotationActionsTemplate"
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<redaction-comments [annotation]="annotation"></redaction-comments>
|
||||
</div>
|
||||
</div>
|
||||
<redaction-annotations-list
|
||||
[canMultiSelect]="!isReadOnly"
|
||||
[annotations]="(displayedAnnotations$ | async)?.get(activeViewerPage)"
|
||||
[selectedAnnotations]="selectedAnnotations"
|
||||
[annotationActionsTemplate]="annotationActionsTemplate"
|
||||
[(multiSelectActive)]="multiSelectActive"
|
||||
[activeViewerPage]="activeViewerPage"
|
||||
(pagesPanelActive)="pagesPanelActive = $event"
|
||||
(selectAnnotations)="selectAnnotations.emit($event)"
|
||||
(deselectAnnotations)="deselectAnnotations.emit($event)"
|
||||
></redaction-annotations-list>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.read-only {
|
||||
padding: 13px 16px;
|
||||
background-color: $primary;
|
||||
color: $white;
|
||||
background-color: variables.$primary;
|
||||
color: variables.$white;
|
||||
justify-content: space-between;
|
||||
|
||||
.read-only-text {
|
||||
@ -48,12 +48,12 @@
|
||||
|
||||
.multi-select {
|
||||
min-height: 40px;
|
||||
background: $primary;
|
||||
background: variables.$primary;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 8px 0 16px;
|
||||
color: $white;
|
||||
color: variables.$white;
|
||||
|
||||
.selected-wrapper {
|
||||
display: flex;
|
||||
@ -90,7 +90,7 @@
|
||||
}
|
||||
|
||||
.quick-navigation {
|
||||
border-right: 1px solid $separator;
|
||||
border-right: 1px solid variables.$separator;
|
||||
min-width: 61px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
@ -105,7 +105,7 @@
|
||||
transition: background-color 0.25s;
|
||||
|
||||
&:not(.disabled):hover {
|
||||
background-color: $grey-6;
|
||||
background-color: variables.$grey-6;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
@ -124,21 +124,21 @@
|
||||
}
|
||||
|
||||
.pages {
|
||||
@include no-scroll-bar;
|
||||
@include common-mixins.no-scroll-bar;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.page-separator {
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: $grey-6;
|
||||
background-color: variables.$grey-6;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
@ -157,96 +157,12 @@
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.annotation-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid $separator;
|
||||
|
||||
.active-bar-marker {
|
||||
min-width: 4px;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.active-icon-marker-container {
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
&:not(.lower-height) .active-bar-marker {
|
||||
background-color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
.annotation {
|
||||
padding: 10px 16px 8px 10px;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
&.removed {
|
||||
text-decoration: line-through;
|
||||
color: $grey-7;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.actions-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 8px;
|
||||
min-height: 34px;
|
||||
padding-left: 18px;
|
||||
|
||||
.comments-counter {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
transition: background-color 0.2s;
|
||||
line-height: 13px;
|
||||
height: 24px;
|
||||
border-radius: 12px;
|
||||
|
||||
mat-icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redaction-type-annotation-icon {
|
||||
margin-top: 6px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-8;
|
||||
|
||||
::ng-deep .annotation-actions {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
}
|
||||
|
||||
&.has-scrollbar:hover .annotation-wrapper .annotation {
|
||||
&.has-scrollbar:hover::ng-deep .annotation-wrapper .annotation {
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,23 +1,10 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Input,
|
||||
Output,
|
||||
QueryList,
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
ViewChildren
|
||||
} from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostListener, Input, Output, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { AnnotationProcessingService } from '../../services/annotation-processing.service';
|
||||
import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
import { CircleButtonTypes, Debounce, FilterService, IconButtonTypes, IqserEventTarget, NestedFilter } from '@iqser/common-ui';
|
||||
import { FileDataModel } from '@models/file/file-data.model';
|
||||
import { CommentsComponent } from '../comments/comments.component';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { WebViewerInstance } from '@pdftron/webviewer';
|
||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||
@ -56,7 +43,6 @@ export class FileWorkloadComponent {
|
||||
@Output() readonly actionPerformed = new EventEmitter<string>();
|
||||
displayedPages: number[] = [];
|
||||
pagesPanelActive = true;
|
||||
@ViewChildren(CommentsComponent) readonly annotationCommentsComponents: QueryList<CommentsComponent>;
|
||||
@ViewChild('annotationsElement') private readonly _annotationsElement: ElementRef;
|
||||
@ViewChild('quickNavigation') private readonly _quickNavigationElement: ElementRef;
|
||||
|
||||
@ -118,15 +104,6 @@ export class FileWorkloadComponent {
|
||||
}
|
||||
}
|
||||
|
||||
isSelected(annotation: AnnotationWrapper) {
|
||||
return this.selectedAnnotations?.find(a => a?.id === annotation.id);
|
||||
}
|
||||
|
||||
toggleExpandComments(annotation: AnnotationWrapper, $event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this.annotationCommentsComponents.find(c => c.annotation === annotation).toggleExpandComments();
|
||||
}
|
||||
|
||||
logAnnotation(annotation: AnnotationWrapper) {
|
||||
console.log(annotation);
|
||||
}
|
||||
@ -156,25 +133,6 @@ export class FileWorkloadComponent {
|
||||
return this.displayedAnnotations;
|
||||
}
|
||||
|
||||
annotationClicked(annotation: AnnotationWrapper, $event: MouseEvent): void {
|
||||
if (($event.target as IqserEventTarget).localName === 'input') {
|
||||
return;
|
||||
}
|
||||
this.pagesPanelActive = false;
|
||||
this.logAnnotation(annotation);
|
||||
if (this.isSelected(annotation)) {
|
||||
this.deselectAnnotations.emit([annotation]);
|
||||
} else {
|
||||
if (($event.ctrlKey || $event.metaKey) && this.selectedAnnotations.length > 0) {
|
||||
this.multiSelectActive = true;
|
||||
}
|
||||
this.selectAnnotations.emit({
|
||||
annotations: [annotation],
|
||||
multiSelect: this.multiSelectActive
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:keyup', ['$event'])
|
||||
handleKeyEvent($event: KeyboardEvent): void {
|
||||
if (
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
|
||||
.needs-work {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
height: 100%;
|
||||
@ -7,13 +7,13 @@
|
||||
flex-direction: column;
|
||||
|
||||
.exclude-pages-input-container {
|
||||
background-color: $grey-6;
|
||||
background-color: variables.$grey-6;
|
||||
padding: 15px 15px 16px 14px;
|
||||
}
|
||||
|
||||
.all-caps-label-container {
|
||||
padding: 8px 16px;
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
}
|
||||
|
||||
.ranges {
|
||||
@ -22,7 +22,7 @@
|
||||
.range {
|
||||
padding-left: 17px;
|
||||
padding-right: 16px;
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
transition: background-color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -34,7 +34,7 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-8;
|
||||
background-color: variables.$grey-8;
|
||||
|
||||
iqser-circle-button {
|
||||
display: initial;
|
||||
@ -43,7 +43,7 @@
|
||||
}
|
||||
|
||||
&.has-scrollbar:hover {
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
overflow: auto;
|
||||
|
||||
.range {
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.page-wrapper {
|
||||
color: $accent;
|
||||
color: variables.$accent;
|
||||
position: relative;
|
||||
padding: 12px 14px 12px 8px;
|
||||
cursor: pointer;
|
||||
border-left: 4px solid transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-2;
|
||||
background-color: variables.$grey-2;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-left: 4px solid $primary;
|
||||
border-left: 4px solid variables.$primary;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
@ -35,15 +35,15 @@
|
||||
}
|
||||
|
||||
&.read {
|
||||
color: $grey-5;
|
||||
color: variables.$grey-5;
|
||||
|
||||
.text {
|
||||
color: $accent;
|
||||
color: variables.$accent;
|
||||
}
|
||||
}
|
||||
|
||||
.dot {
|
||||
background: $primary;
|
||||
background: variables.$primary;
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
border-radius: 50%;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.page {
|
||||
display: flex;
|
||||
@ -28,9 +28,9 @@
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
background: $white;
|
||||
color: $grey-7;
|
||||
border: 1px solid $grey-7;
|
||||
background: variables.$white;
|
||||
color: variables.$grey-7;
|
||||
border: 1px solid variables.$grey-7;
|
||||
border-radius: 8px;
|
||||
padding: 6px 2px;
|
||||
display: flex;
|
||||
@ -56,7 +56,7 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
color: $grey-7;
|
||||
color: variables.$grey-7;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
border: none;
|
||||
@ -67,7 +67,7 @@
|
||||
&:hover,
|
||||
&:focus {
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid $grey-7;
|
||||
border-bottom: 1px solid variables.$grey-7;
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@
|
||||
padding-right: 4px;
|
||||
|
||||
&:hover {
|
||||
color: $accent;
|
||||
color: variables.$accent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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'
|
||||
});
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<mat-label>{{ 'assign-dossier-owner.dialog.single-user' | translate }}</mat-label>
|
||||
<mat-select formControlName="owner">
|
||||
<mat-option *ngFor="let userId of ownersSelectOptions" [value]="userId">
|
||||
{{ userService.getNameForId(userId) }}
|
||||
{{ userId | name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'common-mixins';
|
||||
@use 'variables';
|
||||
|
||||
.search-container {
|
||||
margin-top: 16px;
|
||||
@ -16,7 +17,7 @@ redaction-team-members {
|
||||
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
}
|
||||
|
||||
> div {
|
||||
@ -51,7 +52,7 @@ redaction-team-members {
|
||||
|
||||
&.selected,
|
||||
&:hover {
|
||||
background-color: $grey-2;
|
||||
background-color: variables.$grey-2;
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.container {
|
||||
flex-wrap: wrap;
|
||||
@ -27,8 +27,8 @@
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background-color: $accent;
|
||||
color: $white;
|
||||
background-color: variables.$accent;
|
||||
color: variables.$white;
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
bottom: -2px;
|
||||
@ -48,6 +48,6 @@
|
||||
|
||||
.see-less {
|
||||
opacity: 1;
|
||||
color: $primary;
|
||||
color: variables.$primary;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
|
||||
.watermark {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<mat-label>{{ 'assign-owner.dialog.label' | translate: { type: data.mode } }}</mat-label>
|
||||
<mat-select formControlName="singleUser">
|
||||
<mat-option *ngFor="let userId of singleUsersSelectOptions" [value]="userId">
|
||||
{{ userService.getNameForId(userId) }}
|
||||
{{ userId | name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
@ -18,7 +18,7 @@
|
||||
height: 100%;
|
||||
width: 1px;
|
||||
padding: 0;
|
||||
background-color: $separator;
|
||||
background-color: variables.$separator;
|
||||
}
|
||||
|
||||
.datepicker-wrapper {
|
||||
@ -60,7 +60,7 @@
|
||||
height: 50px;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
border: 1px solid $grey-5;
|
||||
border: 1px solid variables.$grey-5;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@import '../../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.instructions {
|
||||
color: $grey-7;
|
||||
color: variables.$grey-7;
|
||||
flex: 1;
|
||||
text-align: end;
|
||||
}
|
||||
@ -11,6 +11,6 @@
|
||||
height: calc(100% - 81px) !important;
|
||||
|
||||
.cdk-virtual-scroll-content-wrapper .table-item > div.cell.filename span {
|
||||
@include line-clamp(1);
|
||||
@include common-mixins.line-clamp(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import '../../../../../../assets/styles/variables';
|
||||
|
||||
.download-includes {
|
||||
margin: 16px 0 10px;
|
||||
font-weight: 500;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.dialog-content {
|
||||
padding: 0;
|
||||
margin-top: 24px;
|
||||
border-top: 1px solid $separator;
|
||||
border-top: 1px solid variables.$separator;
|
||||
display: flex;
|
||||
height: calc(90vh - 81px);
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
.content {
|
||||
padding: 24px 32px;
|
||||
overflow: auto;
|
||||
@include scroll-bar;
|
||||
@include common-mixins.scroll-bar;
|
||||
height: calc(100% - 81px);
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
@import '../../../../../../assets/styles/variables';
|
||||
|
||||
.watermark {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
@ -49,6 +49,9 @@ import { DossiersService } from './services/dossiers.service';
|
||||
import { DossierDetailsStatsComponent } from './components/dossier-details-stats/dossier-details-stats.component';
|
||||
import { SearchScreenComponent } from './screens/search-screen/search-screen.component';
|
||||
import { EditDossierDeletedDocumentsComponent } from './dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component';
|
||||
import { AnnotationsListComponent } from './components/file-workload/components/annotations-list/annotations-list.component';
|
||||
import { AnnotationSourceComponent } from './components/file-workload/components/annotation-source/annotation-source.component';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
|
||||
const screens = [DossierListingScreenComponent, DossierOverviewScreenComponent, FilePreviewScreenComponent, SearchScreenComponent];
|
||||
|
||||
@ -89,6 +92,8 @@ const components = [
|
||||
PageExclusionComponent,
|
||||
DossierDetailsStatsComponent,
|
||||
EditDossierDeletedDocumentsComponent,
|
||||
AnnotationsListComponent,
|
||||
AnnotationSourceComponent,
|
||||
|
||||
...screens,
|
||||
...dialogs
|
||||
@ -109,6 +114,6 @@ const services = [
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
providers: [...services],
|
||||
imports: [CommonModule, SharedModule, FileUploadDownloadModule, DossiersRoutingModule]
|
||||
imports: [CommonModule, SharedModule, FileUploadDownloadModule, DossiersRoutingModule, OverlayModule]
|
||||
})
|
||||
export class DossiersModule {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.file-upload-input {
|
||||
display: none;
|
||||
@ -9,7 +9,7 @@
|
||||
&.last-opened {
|
||||
> .selection-column {
|
||||
padding-left: 6px !important;
|
||||
border-left: 4px solid $primary;
|
||||
border-left: 4px solid variables.$primary;
|
||||
}
|
||||
|
||||
> div {
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
> div.cell {
|
||||
.error {
|
||||
color: $primary;
|
||||
color: variables.$primary;
|
||||
}
|
||||
|
||||
.table-item-title {
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
.primary-attribute {
|
||||
padding-top: 6px;
|
||||
@include line-clamp(1);
|
||||
@include common-mixins.line-clamp(1);
|
||||
}
|
||||
|
||||
&.extend-cols {
|
||||
@ -59,7 +59,7 @@
|
||||
|
||||
@keyframes red-fading-background {
|
||||
0% {
|
||||
background-color: rgba($primary, 0.1);
|
||||
background-color: rgba(variables.$primary, 0.1);
|
||||
}
|
||||
100% {
|
||||
background-color: inherit;
|
||||
@ -67,7 +67,7 @@
|
||||
}
|
||||
|
||||
.view-mode-selection {
|
||||
border-right: 1px solid $separator;
|
||||
border-right: 1px solid variables.$separator;
|
||||
padding-right: 16px;
|
||||
margin-right: 16px !important;
|
||||
display: flex;
|
||||
@ -94,7 +94,7 @@
|
||||
|
||||
.filename {
|
||||
font-weight: 600;
|
||||
@include line-clamp(1);
|
||||
@include common-mixins.line-clamp(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,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,
|
||||
@ -52,7 +52,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { annotationFilterChecker } from '@utils/filter-utils';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { DossierWrapper } from '../../../../state/model/dossier.wrapper';
|
||||
import { DossierWrapper } from '@state/model/dossier.wrapper';
|
||||
import { Router } from '@angular/router';
|
||||
import { FileActionService } from '../../services/file-action.service';
|
||||
import StatusEnum = FileStatus.StatusEnum;
|
||||
@ -106,7 +106,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,
|
||||
@ -339,7 +339,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>[] = [];
|
||||
@ -555,7 +555,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',
|
||||
|
||||
@ -88,6 +88,7 @@
|
||||
<div class="vertical-line"></div>
|
||||
|
||||
<redaction-file-actions
|
||||
#fileActions
|
||||
(actionPerformed)="fileActionPerformed($event)"
|
||||
[activeDocumentInfo]="viewDocumentInfo"
|
||||
[activeExcludePages]="excludePages"
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.vertical-line {
|
||||
width: 1px;
|
||||
height: 30px;
|
||||
background-color: $grey-4;
|
||||
background-color: variables.$grey-4;
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
::ng-deep .right-title {
|
||||
height: 70px;
|
||||
display: flex;
|
||||
border-bottom: 1px solid $separator;
|
||||
border-bottom: 1px solid variables.$separator;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 24px;
|
||||
|
||||
@ -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,8 @@ 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 { FileActionsComponent } from '../../components/file-actions/file-actions.component';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
|
||||
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f'];
|
||||
|
||||
@ -78,6 +80,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
static: true
|
||||
})
|
||||
private readonly _filterTemplate: TemplateRef<NestedFilter>;
|
||||
@ViewChild('fileActions') fileActions: FileActionsComponent;
|
||||
|
||||
constructor(
|
||||
readonly appStateService: AppStateService,
|
||||
@ -131,7 +134,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;
|
||||
}
|
||||
@ -257,14 +260,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
this.displayPDFViewer = true;
|
||||
this._updateCanPerformActions();
|
||||
this._subscribeToFileUpdates();
|
||||
|
||||
if (this.fileData?.fileStatus?.analysisRequired) {
|
||||
this.fileActions.reanalyseFile();
|
||||
}
|
||||
}
|
||||
|
||||
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 +351,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 +559,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 +578,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();
|
||||
}
|
||||
|
||||
@ -595,6 +605,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
|
||||
private async _loadFileData(performUpdate = false): Promise<void> {
|
||||
const fileData = await this._fileDownloadService.loadActiveFileData().toPromise();
|
||||
|
||||
if (!fileData.fileStatus?.isPending && !fileData.fileStatus?.isError) {
|
||||
if (performUpdate) {
|
||||
this.fileData.redactionLog = fileData.redactionLog;
|
||||
@ -678,9 +689,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 +712,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) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<section *ngIf="searchResults$ | async as searchResult">
|
||||
<section *ngIf="searchResults$ | async">
|
||||
<redaction-page-header
|
||||
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
|
||||
[searchPlaceholder]="'search.placeholder' | translate"
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
|
||||
.highlights {
|
||||
@include line-clamp(1);
|
||||
@include common-mixins.line-clamp(1);
|
||||
|
||||
em {
|
||||
background-color: #fffcc4;
|
||||
|
||||
@ -16,8 +16,8 @@ import { RouterHistoryService } from '@services/router-history.service';
|
||||
interface ListItem extends Listable {
|
||||
readonly dossierId: string;
|
||||
readonly filename: string;
|
||||
readonly unmatched: string[] | null;
|
||||
readonly highlights: { [key: string]: string[] };
|
||||
readonly unmatched: readonly string[] | null;
|
||||
readonly highlights: Record<string, readonly string[]>;
|
||||
readonly routerLink: string;
|
||||
readonly status: string;
|
||||
readonly dossierName: string;
|
||||
@ -25,8 +25,8 @@ interface ListItem extends Listable {
|
||||
}
|
||||
|
||||
interface SearchInput {
|
||||
query: string;
|
||||
dossierIds?: string[];
|
||||
readonly query: string;
|
||||
readonly dossierIds?: readonly string[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -37,10 +37,12 @@ interface SearchInput {
|
||||
export class SearchScreenComponent extends ListingComponent<ListItem> implements OnDestroy, OnInit {
|
||||
readonly fileStatusTranslations = fileStatusTranslations;
|
||||
readonly searchPositions = SearchPositions;
|
||||
@ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef<never>;
|
||||
@ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef<never>;
|
||||
@ViewChild('dossierTemplate', { static: true }) dossierTemplate: TemplateRef<never>;
|
||||
@ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef<never>;
|
||||
|
||||
@ViewChild('filenameTemplate', { static: true }) readonly filenameTemplate: TemplateRef<unknown>;
|
||||
@ViewChild('statusTemplate', { static: true }) readonly statusTemplate: TemplateRef<unknown>;
|
||||
@ViewChild('dossierTemplate', { static: true }) readonly dossierTemplate: TemplateRef<unknown>;
|
||||
@ViewChild('pagesTemplate', { static: true }) readonly pagesTemplate: TemplateRef<unknown>;
|
||||
|
||||
readonly tableHeaderLabel = _('search-screen.table-header');
|
||||
tableColumnConfigs: TableColumnConfig<ListItem>[];
|
||||
readonly search$ = new BehaviorSubject<SearchInput>(null);
|
||||
@ -68,6 +70,7 @@ export class SearchScreenComponent extends ListingComponent<ListItem> implements
|
||||
this.filterService.addFilterGroup({
|
||||
slug: 'dossiers',
|
||||
label: this._translateService.instant('search-screen.filters.by-dossier'),
|
||||
filterceptionPlaceholder: this._translateService.instant('search-screen.filters.search-placeholder'),
|
||||
icon: 'red:folder',
|
||||
filters: this._appStateService.allDossiers.map(dossier => ({
|
||||
key: dossier.dossierId,
|
||||
@ -118,7 +121,7 @@ export class SearchScreenComponent extends ListingComponent<ListItem> implements
|
||||
|
||||
private _search(searchInput: SearchInput): Observable<SearchResult> {
|
||||
return this._searchControllerService.search({
|
||||
dossierIds: searchInput.dossierIds,
|
||||
dossierIds: [...searchInput.dossierIds],
|
||||
queryString: searchInput.query ?? '',
|
||||
page: 1,
|
||||
returnSections: false,
|
||||
@ -161,7 +164,7 @@ export class SearchScreenComponent extends ListingComponent<ListItem> implements
|
||||
dossierId,
|
||||
unmatched: unmatchedTerms || null,
|
||||
highlights,
|
||||
status,
|
||||
status: fileWrapper.status,
|
||||
numberOfPages: fileWrapper.numberOfPages,
|
||||
dossierName: this._getDossierWrapper(dossierId).dossierName,
|
||||
filename: fileWrapper.filename,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,14 @@ export class AnnotationDrawService {
|
||||
private readonly _userPreferenceService: UserPreferenceService
|
||||
) {}
|
||||
|
||||
drawAnnotations(
|
||||
activeViewer: WebViewerInstance,
|
||||
annotationWrappers: AnnotationWrapper[],
|
||||
hideSkipped: boolean = false,
|
||||
compareMode: boolean = false
|
||||
) {
|
||||
const annotations = [];
|
||||
annotationWrappers.forEach(annotation => {
|
||||
annotations.push(this.computeAnnotation(activeViewer, annotation, hideSkipped, compareMode));
|
||||
});
|
||||
|
||||
const annotationManager = activeViewer.annotManager;
|
||||
drawAnnotations(activeViewer: WebViewerInstance, annotationWrappers: AnnotationWrapper[], hideSkipped = false, compareMode = false) {
|
||||
if (!activeViewer) {
|
||||
return;
|
||||
}
|
||||
const annotations = annotationWrappers.map(annotation =>
|
||||
this.computeAnnotation(activeViewer, annotation, hideSkipped, compareMode)
|
||||
);
|
||||
const annotationManager = activeViewer.Core.annotationManager;
|
||||
annotationManager.addAnnotations(annotations, { imported: true });
|
||||
annotationManager.drawAnnotationsFromList(annotations);
|
||||
|
||||
@ -49,14 +46,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 +72,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 +88,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 +118,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 +134,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 +155,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { catchError, map, tap } from 'rxjs/operators';
|
||||
import {
|
||||
FileManagementControllerService,
|
||||
ManualRedactionControllerService,
|
||||
@ -24,10 +24,14 @@ export class PdfViewerDataService {
|
||||
) {}
|
||||
|
||||
loadActiveFileRedactionLog() {
|
||||
return this._redactionLogControllerService.getRedactionLog(
|
||||
this._appStateService.activeDossierId,
|
||||
this._appStateService.activeFileId
|
||||
);
|
||||
return this._redactionLogControllerService
|
||||
.getRedactionLog(this._appStateService.activeDossierId, this._appStateService.activeFileId)
|
||||
.pipe(
|
||||
tap(
|
||||
redactionLog => redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page),
|
||||
catchError(() => of({}))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
loadActiveFileData(): Observable<FileDataModel> {
|
||||
@ -35,7 +39,7 @@ export class PdfViewerDataService {
|
||||
const fileId = this._appStateService.activeFileId;
|
||||
|
||||
const file$ = this.downloadOriginalFile(this._appStateService.activeFile);
|
||||
const reactionLog$ = this._redactionLogControllerService.getRedactionLog(dossierId, fileId).pipe(catchError(() => of({})));
|
||||
const reactionLog$ = this.loadActiveFileRedactionLog();
|
||||
const redactionChangeLog$ = this._redactionLogControllerService
|
||||
.getRedactionChangeLog(dossierId, fileId)
|
||||
.pipe(catchError(() => of({})));
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ export class IconsModule {
|
||||
constructor(private readonly _iconRegistry: MatIconRegistry, private readonly _sanitizer: DomSanitizer) {
|
||||
const icons = [
|
||||
'add',
|
||||
'ai',
|
||||
'analyse',
|
||||
'approved',
|
||||
'arrow-right',
|
||||
@ -62,6 +63,7 @@ export class IconsModule {
|
||||
'reason',
|
||||
'remove-from-dict',
|
||||
'report',
|
||||
'rule',
|
||||
'secret',
|
||||
'status',
|
||||
'status-collapse',
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.icon {
|
||||
height: 16px;
|
||||
@ -11,7 +11,7 @@
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
color: $white;
|
||||
color: variables.$white;
|
||||
position: relative;
|
||||
background-color: var(--color);
|
||||
}
|
||||
@ -60,9 +60,9 @@
|
||||
}
|
||||
|
||||
.skipped {
|
||||
background-color: $grey-5;
|
||||
background-color: variables.$grey-5;
|
||||
}
|
||||
|
||||
.none {
|
||||
color: $accent;
|
||||
color: variables.$accent;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
button {
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
&[aria-expanded='true'] {
|
||||
button {
|
||||
background: rgba($primary, 0.1);
|
||||
background: rgba(variables.$primary, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
width: 100%;
|
||||
@ -78,7 +78,7 @@ ngx-monaco-editor {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 8px;
|
||||
color: $accent;
|
||||
color: variables.$accent;
|
||||
|
||||
.with-input {
|
||||
display: flex;
|
||||
@ -106,7 +106,7 @@ ngx-monaco-editor {
|
||||
padding: 0 100px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
border: 1px solid $grey-5;
|
||||
border: 1px solid variables.$grey-5;
|
||||
|
||||
> mat-icon {
|
||||
height: 60px;
|
||||
@ -116,6 +116,6 @@ ngx-monaco-editor {
|
||||
}
|
||||
|
||||
.heading-l {
|
||||
color: $grey-7;
|
||||
color: variables.$grey-7;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
@ -15,5 +15,5 @@
|
||||
}
|
||||
|
||||
.border {
|
||||
border: 1px solid $grey-7;
|
||||
border: 1px solid variables.$grey-7;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $primary;
|
||||
color: variables.$primary;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
border-radius: 8px;
|
||||
border: 1px solid $grey-5;
|
||||
border: 1px solid variables.$grey-5;
|
||||
min-height: 100%;
|
||||
display: block;
|
||||
|
||||
&.ng-invalid {
|
||||
border-color: rgba($primary, 0.3);
|
||||
border-color: rgba(variables.$primary, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,23 +47,23 @@ mat-chip {
|
||||
}
|
||||
|
||||
.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary {
|
||||
background-color: $grey-6;
|
||||
color: $accent;
|
||||
background-color: variables.$grey-6;
|
||||
color: variables.$accent;
|
||||
}
|
||||
|
||||
.mat-chip.mat-standard-chip {
|
||||
background-color: $white;
|
||||
color: $accent;
|
||||
background-color: variables.$white;
|
||||
color: variables.$accent;
|
||||
margin: 0 0 2px 0;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-8;
|
||||
background-color: variables.$grey-8;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-chip.mat-standard-chip::after {
|
||||
background: $grey-8;
|
||||
background: variables.$grey-8;
|
||||
}
|
||||
|
||||
.mat-standard-chip:focus::after {
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
@import '../../../../../assets/styles/variables';
|
||||
@import 'libs/common-ui/src/assets/styles/mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
min-width: 200px;
|
||||
max-width: 200px;
|
||||
background-color: $grey-2;
|
||||
border-right: 1px solid $separator;
|
||||
background-color: variables.$grey-2;
|
||||
border-right: 1px solid variables.$separator;
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
@include no-scroll-bar;
|
||||
@include common-mixins.no-scroll-bar;
|
||||
|
||||
.all-caps-label {
|
||||
padding: 16px;
|
||||
@ -26,12 +26,12 @@
|
||||
font-weight: 500;
|
||||
|
||||
&:not(.active):hover {
|
||||
background-color: rgba($primary, 0.2);
|
||||
background-color: rgba(variables.$primary, 0.2);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $primary;
|
||||
color: $white;
|
||||
background-color: variables.$primary;
|
||||
color: variables.$white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user