This commit is contained in:
Dan Percic 2024-06-17 19:15:56 +03:00
parent 20a80933b5
commit 97ebca5046
12 changed files with 967 additions and 3168 deletions

View File

@ -36,12 +36,13 @@
"prefix": "redaction",
"targets": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"builder": "@angular/build:application",
"options": {
"outputPath": "dist/apps/red-ui",
"outputPath": {
"base": "dist/apps/red-ui"
},
"index": "apps/red-ui/src/index.html",
"main": "apps/red-ui/src/main.ts",
"polyfills": "apps/red-ui/src/polyfills.ts",
"polyfills": ["apps/red-ui/src/polyfills.ts"],
"tsConfig": "tsconfig.json",
"baseHref": "/ui/",
"assets": [
@ -72,13 +73,12 @@
"stylePreprocessorOptions": {
"includePaths": ["./apps/red-ui/src/assets/styles", "./libs/common-ui/src/assets/styles"]
},
"scripts": ["node_modules/@pdftron/webviewer/webviewer.min.js", "node_modules/chart.js/dist/chart.js"],
"vendorChunk": true,
"scripts": ["node_modules/@pdftron/webviewer/webviewer.min.js", "node_modules/chart.js/auto/auto.cjs"],
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
"namedChunks": true,
"browser": "apps/red-ui/src/main.ts"
},
"configurations": {
"production": {
@ -100,8 +100,6 @@
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
@ -114,13 +112,12 @@
"maximumError": "20kb"
}
],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
"serviceWorker": "ngsw-config.json"
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "@angular/build:dev-server",
"options": {
"buildTarget": "red-ui:build"
},

View File

@ -1,18 +1,18 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { IComponentLogEntry } from '@red/domain';
import { FormsModule } from '@angular/forms';
import { CircleButtonComponent, IconButtonComponent, IconButtonTypes, IqserDialog } from '@iqser/common-ui';
import { FilterService } from '@common-ui/filtering';
import { RevertValueDialogComponent } from '../../dialogs/docu-mine/revert-value-dialog/revert-value-dialog.component';
import { CdkDrag, CdkDragDrop, CdkDragHandle, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
import { KeyValuePipe, NgClass, NgForOf, NgIf } from '@angular/common';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatIcon } from '@angular/material/icon';
import { FilterService } from '@common-ui/filtering';
import { CircleButtonComponent, IconButtonComponent, IconButtonTypes, IqserDialog } from '@iqser/common-ui';
import { TranslateModule } from '@ngx-translate/core';
import { IComponentLogEntry } from '@red/domain';
import { RevertValueDialogComponent } from '../../dialogs/docu-mine/revert-value-dialog/revert-value-dialog.component';
@Component({
selector: 'redaction-editable-structured-component-value [entry] [canEdit]',
templateUrl: './editable-structured-component-value.component.html',
styleUrls: ['/editable-structured-component-value.component.scss'],
styleUrls: ['./editable-structured-component-value.component.scss'],
standalone: true,
imports: [
CircleButtonComponent,
@ -30,26 +30,48 @@ import { TranslateModule } from '@ngx-translate/core';
],
})
export class EditableStructuredComponentValueComponent implements OnInit {
protected entryLabel: string;
protected editing = false;
protected hasUpdatedValues = false;
protected initialEntry: IComponentLogEntry;
protected readonly iconButtonTypes = IconButtonTypes;
@Input() entry: IComponentLogEntry;
@Input() canEdit: boolean;
@Output() readonly deselectLast = new EventEmitter();
@Output() readonly overrideValue = new EventEmitter<IComponentLogEntry>();
@Output() readonly revertOverride = new EventEmitter<string>();
selected = false;
protected entryLabel: string;
protected editing = false;
protected hasUpdatedValues = false;
protected initialEntry: IComponentLogEntry;
protected readonly iconButtonTypes = IconButtonTypes;
constructor(
private readonly _filtersService: FilterService,
private readonly _iqserDialog: IqserDialog,
) {}
get disabled() {
for (let i = 0; i < this.entry.componentValues.length; i++) {
if (this.entry.componentValues[i].value !== this.initialEntry.componentValues[i]?.value) {
return false;
}
}
return this.entry.componentValues.length === this.initialEntry.componentValues.length;
}
get #hasUpdatedValues() {
for (const value of this.entry.componentValues) {
if (value.originalValue === null && value.value === '') {
continue;
}
if (value.originalValue !== value.value) {
return true;
}
}
return false;
}
get #initialEntry() {
return JSON.parse(JSON.stringify(this.entry));
}
ngOnInit() {
this.reset();
}
@ -90,15 +112,6 @@ export class EditableStructuredComponentValueComponent implements OnInit {
this.entry.componentValues.splice(index, 1);
}
get disabled() {
for (let i = 0; i < this.entry.componentValues.length; i++) {
if (this.entry.componentValues[i].value !== this.initialEntry.componentValues[i]?.value) {
return false;
}
}
return this.entry.componentValues.length === this.initialEntry.componentValues.length;
}
save() {
this.entry.overridden = true;
this.overrideValue.emit(this.entry);
@ -136,22 +149,6 @@ export class EditableStructuredComponentValueComponent implements OnInit {
return value.replace(/\n/g, '<br>');
}
get #hasUpdatedValues() {
for (const value of this.entry.componentValues) {
if (value.originalValue === null && value.value === '') {
continue;
}
if (value.originalValue !== value.value) {
return true;
}
}
return false;
}
get #initialEntry() {
return JSON.parse(JSON.stringify(this.entry));
}
#setWorkloadFilters() {
this._filtersService.deactivateFilters({ primaryFiltersSlug: 'primaryFilters' });

View File

@ -11,49 +11,38 @@ import {
OnInit,
ViewChild,
} from '@angular/core';
import { Roles } from '@users/roles';
import {
CircleButtonTypes,
getConfig,
HelpModeService,
IqserDialog,
IqserPermissionsService,
isIqserDevMode,
LoadingService,
} from '@iqser/common-ui';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { CircleButtonTypes, getConfig, HelpModeService, IqserPermissionsService, isIqserDevMode, LoadingService } from '@iqser/common-ui';
import { Bind, Debounce, OnDetach } from '@iqser/common-ui/lib/utils';
import { File } from '@red/domain';
import { FileManagementService } from '@services/files/file-management.service';
import { PermissionsService } from '@services/permissions.service';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { UserPreferenceService } from '@users/user-preference.service';
import JSZip from 'jszip';
import { Roles } from '@users/roles';
import { download } from '@utils/file-download-utils';
import { saveAs } from 'file-saver';
import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
import JSZip from 'jszip';
import { firstValueFrom } from 'rxjs';
import { AnnotationDrawService } from '../../../pdf-viewer/services/annotation-draw.service';
import { TablesService } from '../../services/tables.service';
import { ALL_HOTKEYS } from '../../utils/constants';
import { Router } from '@angular/router';
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
import { AnnotationActionsService } from '../../services/annotation-actions.service';
import { FileDataService } from '../../services/file-data.service';
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
import { MatDialog } from '@angular/material/dialog';
import { download } from '@utils/file-download-utils';
import { firstValueFrom } from 'rxjs';
import { FileManagementService } from '@services/files/file-management.service';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { MultiSelectService } from '../../services/multi-select.service';
import { TablesService } from '../../services/tables.service';
import { ALL_HOTKEYS } from '../../utils/constants';
@Component({
selector: 'redaction-file-header',
templateUrl: './file-header.component.html',
styleUrls: ['/file-header.component.scss'],
styleUrls: ['./file-header.component.scss'],
})
export class FileHeaderComponent implements OnInit, AfterViewInit, OnDetach, OnDestroy {
@ViewChild('actionsWrapper', { static: false }) private readonly _actionsWrapper: ElementRef;
@Input() file: File;
protected readonly roles = Roles;
protected readonly circleButtonTypes = CircleButtonTypes;
@Input() file: File;
readonly lastAssignee = computed(() => this.getLastAssignee());
readonly isIqserDevMode = isIqserDevMode();
readonly isDocumine = getConfig().IS_DOCUMINE;

View File

@ -1,55 +1,48 @@
import { Component, Input, OnInit, signal, ViewChildren } from '@angular/core';
import { ComponentLogEntry, Dictionary, File, IComponentLogEntry, WorkflowFileStatuses } from '@red/domain';
import { toObservable } from '@angular/core/rxjs-interop';
import { FilterService } from '@common-ui/filtering';
import { List } from '@common-ui/utils';
import { IconButtonTypes, LoadingService } from '@iqser/common-ui';
import { ComponentLogEntry, Dictionary, File, IComponentLogEntry, WorkflowFileStatuses } from '@red/domain';
import { ComponentLogService } from '@services/files/component-log.service';
import { FilesMapService } from '@services/files/files-map.service';
import { UserPreferenceService } from '@users/user-preference.service';
import { combineLatest, firstValueFrom, Observable } from 'rxjs';
import { List } from '@common-ui/utils';
import { EditableStructuredComponentValueComponent } from '../editable-structured-component-value/editable-structured-component-value.component';
import { FilterService } from '@common-ui/filtering';
import { ComponentLogFilterService } from '../../services/component-log-filter.service';
import { map } from 'rxjs/operators';
import { toObservable } from '@angular/core/rxjs-interop';
import { ComponentLogFilterService } from '../../services/component-log-filter.service';
import { EditableStructuredComponentValueComponent } from '../editable-structured-component-value/editable-structured-component-value.component';
@Component({
selector: 'redaction-structured-component-management',
templateUrl: './structured-component-management.component.html',
styleUrls: ['/structured-component-management.component.scss'],
styleUrls: ['./structured-component-management.component.scss'],
})
export class StructuredComponentManagementComponent implements OnInit {
@Input() file: File;
@Input() dictionaries: Dictionary[];
@ViewChildren('editableComponent') editableComponents: List<EditableStructuredComponentValueComponent>;
protected readonly componentLogData = signal<ComponentLogEntry[] | undefined>(undefined);
protected readonly componentLogData$ = toObservable(this.componentLogData);
protected readonly openScmDialogByDefault = signal(this.userPreferences.getOpenScmDialogByDefault());
protected readonly iconButtonTypes = IconButtonTypes;
protected displayedComponents$: Observable<ComponentLogEntry[]>;
@Input() file: File;
@Input() dictionaries: Dictionary[];
@ViewChildren('editableComponent') editableComponents: List<EditableStructuredComponentValueComponent>;
constructor(
private readonly _componentLogService: ComponentLogService,
private readonly _filesMapService: FilesMapService,
private readonly _loadingService: LoadingService,
private readonly _componentLogFilterService: ComponentLogFilterService,
private readonly _filterService: FilterService,
readonly userPreferences: UserPreferenceService,
) {}
get canEdit() {
return this.file.workflowStatus !== WorkflowFileStatuses.APPROVED;
}
async ngOnInit(): Promise<void> {
await this.#loadData();
this.displayedComponents$ = this.#displayedComponents$();
}
#displayedComponents$() {
const componentLogFilters$ = this._filterService.getFilterModels$('componentLogFilters');
return combineLatest([this.componentLogData$, componentLogFilters$]).pipe(
map(([components, filters]) => this._componentLogFilterService.filterComponents(components, filters)),
);
}
deselectLast() {
const lastSelected = this.editableComponents.find(c => c.selected);
if (lastSelected) {
@ -57,10 +50,6 @@ export class StructuredComponentManagementComponent implements OnInit {
}
}
get canEdit() {
return this.file.workflowStatus !== WorkflowFileStatuses.APPROVED;
}
async toggleOpenScmDialogByDefault() {
await this.userPreferences.toggleOpenScmDialogByDefault();
await this.userPreferences.reload();
@ -83,6 +72,13 @@ export class StructuredComponentManagementComponent implements OnInit {
await this.#loadData();
}
#displayedComponents$() {
const componentLogFilters$ = this._filterService.getFilterModels$('componentLogFilters');
return combineLatest([this.componentLogData$, componentLogFilters$]).pipe(
map(([components, filters]) => this._componentLogFilterService.filterComponents(components, filters)),
);
}
async #loadData(): Promise<void> {
this._loadingService.start();
const componentLogData = await firstValueFrom(

View File

@ -2170,7 +2170,7 @@
"display-name": "This placeholder is replaced by the type of redaction (entity)."
},
"excerpt": "This placeholder is replaced by a text snippet that contains the redaction.",
"is-skipped": "The skipped redaction placeholder indicates whether a redaction is skipped or not. It can be included in a separate column of a template that also contains the {{redaction.value}} placeholder. The placeholder is replaced by “true” if the respective redaction is skipped, and by “false” if it is redacted (i. e., not skipped).",
"is-skipped": "The skipped redaction placeholder indicates whether a redaction is skipped or not. It can be included in a separate column of a template that also contains the '{{redaction.value'}} placeholder. The placeholder is replaced by “true” if the respective redaction is skipped, and by “false” if it is redacted (i. e., not skipped).",
"justification": "This placeholder is replaced by the justification of the redaction. It is a combination of the legal basis (justificationParagraph) and the justification text (justificationReason).",
"justification-legal-basis": "This placeholder is replaced by the legal basis for the redaction.",
"justification-paragraph": "This placeholder is replaced by the legal basis for the redaction.",
@ -2552,4 +2552,4 @@
}
},
"yesterday": "Yesterday"
}
}

View File

@ -2552,4 +2552,4 @@
}
},
"yesterday": "Yesterday"
}
}

View File

@ -39,11 +39,11 @@ $red-palette: (
),
);
$gn-next-primary: mat.define-palette($primary-palette, default, lighter, darker, text);
$gn-next-secondary: mat.define-palette($secondary-palette, default, lighter, darker, text);
$gn-next-warning: mat.define-palette($red-palette, default, lighter, darker, text);
$gn-next-primary: mat.m2-define-palette($primary-palette, default, lighter, darker, text);
$gn-next-secondary: mat.m2-define-palette($secondary-palette, default, lighter, darker, text);
$gn-next-warning: mat.m2-define-palette($red-palette, default, lighter, darker, text);
$light-theme: mat.define-light-theme(
$light-theme: mat.m2-define-light-theme(
(
color: (
primary: $gn-next-primary,
@ -53,7 +53,7 @@ $light-theme: mat.define-light-theme(
)
);
$dark-theme: mat.define-dark-theme(
$dark-theme: mat.m2-define-dark-theme(
(
color: (
primary: $gn-next-primary,
@ -66,11 +66,11 @@ $dark-theme: mat.define-dark-theme(
@include mat.core-theme($light-theme);
@include mat.all-component-themes($light-theme);
$custom-typography: mat.define-typography-config(
$custom-typography: mat.m2-define-typography-config(
$font-family: 'Inter, sans-serif',
$body-1: mat.define-typography-level(13px, 18px, 400),
$body-2: mat.define-typography-level(13px, 18px, 400),
$button: mat.define-typography-level(13px, 13px, 400),
$body-1: mat.m2-define-typography-level(13px, 18px, 400),
$body-2: mat.m2-define-typography-level(13px, 18px, 400),
$button: mat.m2-define-typography-level(13px, 13px, 400),
);
@include mat.all-component-typographies($custom-typography);

@ -1 +1 @@
Subproject commit 748cce403285c97e14cd3115a828c94c9d5d4520
Subproject commit 213cabce7a65ac0cdf89d1578f442b304e5a97e1

View File

@ -1,5 +1,5 @@
import * as dayjs from 'dayjs';
import { getLeftDateTime } from '@iqser/common-ui/lib/utils';
import dayjs from 'dayjs';
export abstract class TrashItem {
abstract readonly type: 'dossier' | 'file';

View File

@ -19,23 +19,23 @@
"*.{ts,js,html}": "eslint --fix"
},
"dependencies": {
"@angular/animations": "17.3.4",
"@angular/cdk": "17.3.4",
"@angular/common": "17.3.4",
"@angular/compiler": "17.3.4",
"@angular/core": "17.3.4",
"@angular/forms": "17.3.4",
"@angular/material": "17.3.4",
"@angular/platform-browser": "17.3.4",
"@angular/platform-browser-dynamic": "17.3.4",
"@angular/router": "17.3.4",
"@angular/service-worker": "17.3.4",
"@angular/animations": "18.0.3",
"@angular/cdk": "18.0.3",
"@angular/common": "18.0.3",
"@angular/compiler": "18.0.3",
"@angular/core": "18.0.3",
"@angular/forms": "18.0.3",
"@angular/material": "18.0.3",
"@angular/platform-browser": "18.0.3",
"@angular/platform-browser-dynamic": "18.0.3",
"@angular/router": "18.0.3",
"@angular/service-worker": "18.0.3",
"@materia-ui/ngx-monaco-editor": "^6.0.0",
"@messageformat/core": "^3.3.0",
"@ngx-translate/core": "15.0.0",
"@ngx-translate/http-loader": "8.0.0",
"@pdftron/webviewer": "10.9.0",
"chart.js": "4.4.2",
"chart.js": "4.4.3",
"dayjs": "1.11.10",
"file-saver": "^2.0.5",
"jszip": "^3.10.1",
@ -59,17 +59,17 @@
"zone.js": "0.14.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "17.3.4",
"@angular-devkit/core": "17.3.4",
"@angular-devkit/schematics": "17.3.4",
"@angular-eslint/builder": "17.3.0",
"@angular-eslint/eslint-plugin": "17.3.0",
"@angular-eslint/eslint-plugin-template": "17.3.0",
"@angular-eslint/schematics": "17.3.0",
"@angular-eslint/template-parser": "17.3.0",
"@angular/cli": "17.3.4",
"@angular/compiler-cli": "17.3.4",
"@angular/language-service": "17.3.4",
"@angular-devkit/core": "18.0.4",
"@angular-devkit/schematics": "18.0.4",
"@angular-eslint/builder": "18.0.1",
"@angular-eslint/eslint-plugin": "18.0.1",
"@angular-eslint/eslint-plugin-template": "18.0.1",
"@angular-eslint/schematics": "18.0.1",
"@angular-eslint/template-parser": "18.0.1",
"@angular/build": "^18.0.4",
"@angular/cli": "18.0.4",
"@angular/compiler-cli": "18.0.3",
"@angular/language-service": "18.0.3",
"@bartholomej/ngx-translate-extract": "^8.0.2",
"@localazy/ts-api": "^1.0.0",
"@schematics/angular": "17.3.4",
@ -89,7 +89,7 @@
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jest-extended": "4.0.2",
"jest-preset-angular": "14.0.3",
"jest-preset-angular": "14.1.0",
"lint-staged": "15.2.2",
"prettier": "3.2.5",
"sonarqube-scanner": "3.4.0",

View File

@ -5,17 +5,17 @@
"resolveJsonModule": true,
"sourceMap": true,
"declaration": false,
"esModuleInterop": true,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"useDefineForClassFields": false,
"strictPropertyInitialization": false,
"importHelpers": true,
"target": "ES2022",
"module": "es2020",
"module": "ES2022",
"typeRoots": ["node_modules/@types"],
"lib": ["es2021", "dom"],
"lib": ["ES2022", "dom"],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",

3866
yarn.lock

File diff suppressed because it is too large Load Diff