Merge branch 'master' into VM/RED-2614

This commit is contained in:
Valentin 2022-01-17 23:42:08 +02:00
commit 5646a7a784
33 changed files with 14668 additions and 1895 deletions

View File

@ -1,7 +1,4 @@
{
"cli": {
"analytics": "4b8eed12-a1e6-4b7a-9ea2-925b27941271"
},
"version": 1,
"projects": {
"common-ui": {

View File

@ -1,6 +1,6 @@
import { AnnotationWrapper } from './annotation.wrapper';
import { isArray } from 'rxjs/internal-compatibility';
import { User } from '@red/domain';
import { isArray } from 'lodash';
export class AnnotationPermissions {
canUndo = true;

View File

@ -12,7 +12,18 @@ import {
import { curveLinear } from 'd3-shape';
import { scaleBand, scaleLinear, scalePoint, scaleTime } from 'd3-scale';
import { BaseChartComponent, calculateViewDimensions, ColorHelper, LineSeriesComponent, ViewDimensions } from '@swimlane/ngx-charts';
import {
BaseChartComponent,
calculateViewDimensions,
Color,
ColorHelper,
LegendPosition,
LineSeriesComponent,
Orientation,
ScaleType,
ViewDimensions,
} from '@swimlane/ngx-charts';
import { ILineChartSeries } from './models';
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
@ -25,7 +36,7 @@ export class ComboChartComponent extends BaseChartComponent {
@Input() curve: any = curveLinear;
@Input() legend = false;
@Input() legendTitle = 'Legend';
@Input() legendPosition = 'right';
@Input() legendPosition: LegendPosition = LegendPosition.Right;
@Input() xAxis;
@Input() yAxis;
@Input() showXAxisLabel;
@ -38,33 +49,33 @@ export class ComboChartComponent extends BaseChartComponent {
@Input() gradient: boolean;
@Input() showGridLines = true;
@Input() activeEntries: any[] = [];
@Input() schemeType: string;
@Input() schemeType: ScaleType;
@Input() xAxisTickFormatting: any;
@Input() yAxisTickFormatting: any;
@Input() yRightAxisTickFormatting: any;
@Input() roundDomains = false;
@Input() colorSchemeLine: any;
@Input() colorSchemeLine: Color;
@Input() autoScale;
@Input() lineChart: any;
@Input() lineChart: ILineChartSeries[];
@Input() yLeftAxisScaleFactor: any;
@Input() yRightAxisScaleFactor: any;
@Input() rangeFillOpacity: number;
@Input() animations = true;
@Input() noBarWhenZero = true;
@Output() activate: EventEmitter<any> = new EventEmitter();
@Output() deactivate: EventEmitter<any> = new EventEmitter();
@Output() activate = new EventEmitter<{ value; entries: unknown[] }>();
@Output() deactivate = new EventEmitter<{ value; entries: unknown[] }>();
@ContentChild('tooltipTemplate') tooltipTemplate: TemplateRef<any>;
@ContentChild('seriesTooltipTemplate') seriesTooltipTemplate: TemplateRef<any>;
@ContentChild('tooltipTemplate') tooltipTemplate: TemplateRef<unknown>;
@ContentChild('seriesTooltipTemplate') seriesTooltipTemplate: TemplateRef<unknown>;
@ViewChild(LineSeriesComponent) lineSeriesComponent: LineSeriesComponent;
dims: ViewDimensions;
xScale: any;
yScale: any;
xDomain: any;
yDomain: any;
xDomain: string[] | number[];
yDomain: string[] | number[];
transform: string;
colors: ColorHelper;
colorsLine: ColorHelper;
@ -72,19 +83,19 @@ export class ComboChartComponent extends BaseChartComponent {
xAxisHeight = 0;
yAxisWidth = 0;
legendOptions: any;
scaleType = 'linear';
scaleType: ScaleType = ScaleType.Linear;
xScaleLine;
yScaleLine;
xDomainLine;
yDomainLine;
seriesDomain;
scaledAxis;
combinedSeries;
combinedSeries: ILineChartSeries[];
xSet;
filteredDomain;
hoveredVertical;
yOrientLeft = 'left';
yOrientRight = 'right';
yOrientLeft: Orientation = Orientation.Left;
yOrientRight: Orientation = Orientation.Right;
legendSpacing = 0;
bandwidth: number;
barPadding = 8;
@ -176,15 +187,11 @@ export class ComboChartComponent extends BaseChartComponent {
return this.combinedSeries.map(d => d.name);
}
isDate(value): boolean {
if (value instanceof Date) {
return true;
}
return false;
isDate(value): value is Date {
return value instanceof Date;
}
getScaleType(values): string {
getScaleType(values): ScaleType {
let date = true;
let num = true;
@ -199,16 +206,16 @@ export class ComboChartComponent extends BaseChartComponent {
}
if (date) {
return 'time';
return ScaleType.Time;
}
if (num) {
return 'linear';
return ScaleType.Linear;
}
return 'ordinal';
return ScaleType.Ordinal;
}
getXDomainLine(): any[] {
let values = [];
let values: number[] = [];
for (const results of this.lineChart) {
for (const d of results.series) {
@ -239,7 +246,7 @@ export class ComboChartComponent extends BaseChartComponent {
}
getYDomainLine(): any[] {
const domain = [];
const domain: number[] = [];
for (const results of this.lineChart) {
for (const d of results.series) {
@ -263,7 +270,7 @@ export class ComboChartComponent extends BaseChartComponent {
const max = Math.max(...domain);
if (this.yRightAxisScaleFactor) {
const minMax = this.yRightAxisScaleFactor(min, max);
return [Math.min(0, minMax.min), minMax.max];
return [Math.min(0, minMax.min as number), minMax.max];
} else {
min = Math.min(0, min);
return [min, max];
@ -317,12 +324,12 @@ export class ComboChartComponent extends BaseChartComponent {
}
getYDomain() {
const values = this.results.map(d => d.value);
const values: number[] = this.results.map(d => d.value);
const min = Math.min(0, ...values);
const max = Math.max(...values);
if (this.yLeftAxisScaleFactor) {
const minMax = this.yLeftAxisScaleFactor(min, max);
return [Math.min(0, minMax.min), minMax.max];
return [Math.min(0, minMax.min as number), minMax.max];
} else {
return [min, max];
}
@ -333,7 +340,7 @@ export class ComboChartComponent extends BaseChartComponent {
}
setColors(): void {
let domain;
let domain: number[] | string[];
if (this.schemeType === 'ordinal') {
domain = this.xDomain;
} else {

View File

@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { animate, style, transition, trigger } from '@angular/animations';
import { formatLabel } from '@swimlane/ngx-charts';
import { Bar, BarOrientation, formatLabel, PlacementTypes, StyleTypes } from '@swimlane/ngx-charts';
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
@ -17,7 +17,7 @@ import { formatLabel } from '@swimlane/ngx-charts';
[fill]="bar.color"
[stops]="bar.gradientStops"
[data]="bar.data"
[orientation]="'vertical'"
[orientation]="orientations.Vertical"
[roundEdges]="bar.roundEdges"
[gradient]="gradient"
[isActive]="isActive(bar.data)"
@ -27,8 +27,8 @@ import { formatLabel } from '@swimlane/ngx-charts';
(deactivate)="deactivate.emit($event)"
ngx-tooltip
[tooltipDisabled]="tooltipDisabled"
[tooltipPlacement]="0"
[tooltipType]="1"
[tooltipPlacement]="tooltipPlacements.Top"
[tooltipType]="tooltipTypes.tooltip"
[tooltipTitle]="bar.tooltipText"
></svg:g>
`,
@ -67,6 +67,9 @@ export class ComboSeriesVerticalComponent implements OnChanges {
bars: any;
x: any;
y: any;
readonly tooltipTypes = StyleTypes;
readonly tooltipPlacements = PlacementTypes;
readonly orientations = BarOrientation;
ngOnChanges(): void {
this.update();
@ -91,7 +94,7 @@ export class ComboSeriesVerticalComponent implements OnChanges {
const formattedLabel = formatLabel(label);
const roundEdges = this.type === 'standard';
const bar: any = {
const bar: Bar = {
value,
label,
roundEdges,
@ -101,8 +104,15 @@ export class ComboSeriesVerticalComponent implements OnChanges {
height: 0,
x: 0,
y: 0,
ariaLabel: label,
tooltipText: label,
color: undefined,
gradientStops: undefined,
};
let offset0 = d0;
let offset1 = offset0 + value;
if (this.type === 'standard') {
bar.height = Math.abs(this.yScale(value) - this.yScale(0));
bar.x = this.xScale(label);
@ -113,18 +123,14 @@ export class ComboSeriesVerticalComponent implements OnChanges {
bar.y = this.yScale(value);
}
} else if (this.type === 'stacked') {
const offset0 = d0;
const offset1 = offset0 + value;
d0 += value;
bar.height = this.yScale(offset0) - this.yScale(offset1);
bar.x = 0;
bar.y = this.yScale(offset1);
bar.offset0 = offset0;
bar.offset1 = offset1;
// bar.offset0 = offset0;
// bar.offset1 = offset1;
} else if (this.type === 'normalized') {
let offset0 = d0;
let offset1 = offset0 + value;
d0 += value;
if (total > 0) {
@ -138,8 +144,8 @@ export class ComboSeriesVerticalComponent implements OnChanges {
bar.height = this.yScale(offset0) - this.yScale(offset1);
bar.x = 0;
bar.y = this.yScale(offset1);
bar.offset0 = offset0;
bar.offset1 = offset1;
// bar.offset0 = offset0;
// bar.offset1 = offset1;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
value = (offset1 - offset0).toFixed(2) + '%';
@ -152,8 +158,8 @@ export class ComboSeriesVerticalComponent implements OnChanges {
bar.color = this.colors.getColor(value);
bar.gradientStops = this.colors.getLinearGradientStops(value);
} else {
bar.color = this.colors.getColor(bar.offset1);
bar.gradientStops = this.colors.getLinearGradientStops(bar.offset1, bar.offset0);
bar.color = this.colors.getColor(offset1);
bar.gradientStops = this.colors.getLinearGradientStops(offset1, offset0);
}
}

View File

@ -0,0 +1,11 @@
export interface ISeries {
name: number;
value: number;
min: number;
max: number;
}
export interface ILineChartSeries {
name: string;
series: ISeries[];
}

View File

@ -6,7 +6,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { UserService } from '@services/user.service';
import { RouterHistoryService } from '@services/router-history.service';
import { DigitalSignatureService } from '../../services/digital-signature.service';
import { IDigitalSignature } from '@red/domain';
import { IDigitalSignature, IDigitalSignatureRequest } from '@red/domain';
import { HttpStatusCode } from '@angular/common/http';
@Component({
@ -40,29 +40,30 @@ export class DigitalSignatureScreenComponent extends AutoUnsubscribe implements
}
saveDigitalSignature() {
const digitalSignature = {
...this.form.getRawValue(),
const formValue = this.form.getRawValue();
const digitalSignature: IDigitalSignature = {
...formValue,
};
//adjusted for chrome auto-complete / password manager
digitalSignature.password = digitalSignature.keySecret;
digitalSignature.password = formValue.keySecret;
const observable = this.digitalSignatureExists
? this._digitalSignatureService.update(digitalSignature)
: this._digitalSignatureService.save(digitalSignature);
this.addSubscription = observable.subscribe(
() => {
this.addSubscription = observable.subscribe({
next: () => {
this.loadDigitalSignatureAndInitializeForm();
this._toaster.success(_('digital-signature-screen.action.save-success'));
},
error => {
error: error => {
if (error.status === HttpStatusCode.BadRequest) {
this._toaster.error(_('digital-signature-screen.action.certificate-not-valid-error'));
} else {
this._toaster.error(_('digital-signature-screen.action.save-error'));
}
},
);
});
}
removeDigitalSignature() {
@ -85,23 +86,23 @@ export class DigitalSignatureScreenComponent extends AutoUnsubscribe implements
this.form.get('certificateName').setValue(file.name);
input.value = null;
};
fileReader.readAsDataURL(file);
fileReader.readAsDataURL(file as Blob);
}
loadDigitalSignatureAndInitializeForm() {
this._loadingService.start();
this.addSubscription = this._digitalSignatureService
this._digitalSignatureService
.getSignature()
.subscribe(
digitalSignature => {
.subscribe({
next: digitalSignature => {
this.digitalSignatureExists = true;
this.digitalSignature = digitalSignature;
},
() => {
error: () => {
this.digitalSignatureExists = false;
this.digitalSignature = {};
},
)
})
.add(() => {
this.form = this._getForm();
this._loadingService.stop();

View File

@ -8,6 +8,7 @@ import { UserService } from '@services/user.service';
import { RouterHistoryService } from '@services/router-history.service';
import { LicenseReportService } from '../../services/licence-report.service';
import { ILicenseReport } from '@red/domain';
import { Color, ScaleType } from '@swimlane/ngx-charts';
@Component({
selector: 'redaction-license-information-screen',
@ -31,14 +32,16 @@ export class LicenseInformationScreenComponent implements OnInit {
analysisPercentageOfLicense = 100;
barChart: any[];
lineChartSeries: any[] = [];
lineChartScheme = {
lineChartScheme: Color = {
name: 'Line chart scheme',
selectable: true,
group: 'Ordinal',
group: ScaleType.Ordinal,
domain: ['#dd4d50', '#5ce594', '#0389ec'],
};
comboBarScheme = {
comboBarScheme: Color = {
name: 'Combo bar scheme',
selectable: true,
group: 'Ordinal',
group: ScaleType.Ordinal,
domain: ['#0389ec'],
};

View File

@ -92,6 +92,28 @@ export class ReportsScreenComponent implements OnInit {
}
const dossierTemplateId = this._dossierTemplatesService.activeDossierTemplateId;
if (this.availableTemplates.some(template => template.fileName === file.name)) {
const data = new ConfirmationDialogInput({
title: _('confirmation-dialog.report-template-same-name.title'),
question: _('confirmation-dialog.report-template-same-name.question'),
confirmationText: _('confirmation-dialog.report-template-same-name.confirmation-text'),
denyText: _('confirmation-dialog.report-template-same-name.deny-text'),
});
this._dialogService.openDialog('confirm', null, data, null, async result => {
if (result) {
await this._openConfirmationDialog(file, dossierTemplateId);
}
});
} else {
await this._openConfirmationDialog(file, dossierTemplateId);
}
this._fileInput.nativeElement.value = null;
}
private async _openConfirmationDialog(file: File, dossierTemplateId: string) {
if (this._isExcelFile(file)) {
const data = new ConfirmationDialogInput({
title: _('confirmation-dialog.upload-report-template.title'),
@ -113,7 +135,6 @@ export class ReportsScreenComponent implements OnInit {
await this._reportTemplateService.uploadTemplateForm(dossierTemplateId, false, file).toPromise();
await this._loadReportTemplates();
}
this._fileInput.nativeElement.value = null;
}
private async _deleteTemplate(template: IReportTemplate) {

View File

@ -28,6 +28,7 @@ export class RedRoleGuard implements CanActivate {
if (
this._userService.currentUser.isUserAdmin &&
!this._userService.currentUser.isAdmin &&
!this._userService.currentUser.isUser &&
!(state.url.startsWith('/main/admin/users') || state.url.startsWith('/main/my-profile'))
) {
this._router.navigate(['/main/admin/users']);

View File

@ -66,9 +66,10 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
async save(): EditDossierSaveResult {
const dossierAttributeList = this.attributes.map(attr => ({
dossierAttributeConfigId: attr.id,
value: this.isSpecificType(attr, DossierAttributeConfigTypes.DATE)
? moment(this.currentAttrValue(attr)).format('YYYY-MM-DD')
: this.currentAttrValue(attr),
value:
this.isSpecificType(attr, DossierAttributeConfigTypes.DATE) && !!this.currentAttrValue(attr)
? moment(this.currentAttrValue(attr)).format('YYYY-MM-DD')
: this.currentAttrValue(attr),
}));
try {
await this._dossierAttributesService.setAttributes(this.dossier, dossierAttributeList).toPromise();

View File

@ -1,6 +1,11 @@
<div class="needs-work">
<redaction-annotation-icon *ngIf="file.analysisRequired" [color]="analysisColor" label="A" type="square"></redaction-annotation-icon>
<redaction-annotation-icon *ngIf="file.hasUpdates" [color]="updatedColor" label="U" type="square"></redaction-annotation-icon>
<redaction-annotation-icon
*ngIf="file.hasUpdates && file.assignee === userService.currentUser.id"
[color]="updatedColor"
label="U"
type="square"
></redaction-annotation-icon>
<redaction-annotation-icon *ngIf="file.hasRedactions" [color]="redactionColor" label="R" type="square"></redaction-annotation-icon>
<redaction-annotation-icon *ngIf="file.hasImages" [color]="imageColor" label="I" type="square"></redaction-annotation-icon>
<redaction-annotation-icon *ngIf="file.hintsOnly" [color]="hintColor" label="H" type="circle"></redaction-annotation-icon>

View File

@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { File } from '@red/domain';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { UserService } from '../../../../../../../services/user.service';
@Component({
selector: 'redaction-file-workload',
@ -12,7 +13,11 @@ import { DossiersService } from '@services/entity-services/dossiers.service';
export class FileWorkloadComponent {
@Input() file: File;
constructor(private readonly _appStateService: AppStateService, private readonly _dossiersService: DossiersService) {}
constructor(
public readonly userService: UserService,
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
) {}
get suggestionColor() {
return this._getDictionaryColor('suggestion');

View File

@ -41,6 +41,7 @@ export class AnnotationsListComponent implements OnChanges {
if (this.canMultiSelect && ($event.ctrlKey || $event.metaKey) && this.selectedAnnotations.length > 0) {
this.multiSelectService.activate();
}
console.log('emit', annotation);
this.selectAnnotations.emit([annotation]);
}
}

View File

@ -208,6 +208,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
if (!file.canBeOpened) {
return this._router.navigate([this._dossiersService.find(this.dossierId)?.routerLink]);
}
this.viewModeService.set('STANDARD');
await this.ngOnInit();
this._lastPage = previousRoute.queryParams.page;
@ -277,7 +278,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
@Debounce(10)
selectAnnotations(annotations?: AnnotationWrapper[]) {
if (annotations) {
this.viewerComponent?.utils?.selectAnnotations(annotations, this.multiSelectService.isActive);
const annotationsToSelect = this.multiSelectService.isActive ? [...this.selectedAnnotations, ...annotations] : annotations;
this.viewerComponent?.utils?.selectAnnotations(annotationsToSelect, this.multiSelectService.isActive);
} else {
this.viewerComponent?.utils?.deselectAllAnnotations();
}
@ -396,7 +398,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
});
// Go to initial page from query params
const pageNumber = this._lastPage || this._activatedRoute.snapshot.queryParams.page;
const pageNumber: string = this._lastPage || this._activatedRoute.snapshot.queryParams.page;
if (pageNumber) {
setTimeout(() => {
this.selectPage(parseInt(pageNumber, 10));
@ -412,6 +414,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
async annotationsChangedByReviewAction(annotation: AnnotationWrapper) {
this.multiSelectService.deactivate();
await this._reloadAnnotationsForPage(annotation?.pageNumber || this.activeViewerPage);
}
@ -516,7 +519,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
await stampPDFPage(
document,
this._instance.Core.PDFNet,
this._translateService.instant('file-preview.excluded-from-redaction'),
this._translateService.instant('file-preview.excluded-from-redaction') as string,
17,
'courier',
'TOP_LEFT',
@ -535,8 +538,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
.pipe(filter(file => file.fileId === this.fileId))
.subscribe(async file => {
if (file.lastProcessed !== this.fileData?.file.lastProcessed) {
const previousAnnotations = this.visibleAnnotations;
await this._loadFileData(file);
await this._reloadAnnotations();
await this._reloadAnnotations(previousAnnotations);
}
this._loadingService.stop();
});
@ -588,13 +592,9 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._workloadComponent?.scrollAnnotations();
}
private async _reloadAnnotations() {
this.fileData.redactionLog = await this._fileDownloadService.loadRedactionLogFor(this.dossierId, this.fileId).toPromise();
this._instance.Core.annotationManager.deleteAnnotations(this._instance.Core.annotationManager.getAnnotationsList(), {
imported: true,
force: true,
});
await this._cleanupAndRedrawAnnotations();
private async _reloadAnnotations(previousAnnotations?: AnnotationWrapper[]) {
this._deleteAnnotations();
await this._cleanupAndRedrawAnnotations(previousAnnotations);
}
private async _reloadAnnotationsForPage(page: number) {
@ -609,22 +609,32 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
const currentPageAnnotations = this.visibleAnnotations.filter(a => a.pageNumber === page);
this.fileData.redactionLog = await this._fileDownloadService.loadRedactionLogFor(this.dossierId, this.fileId).toPromise();
this._deleteAnnotations(currentPageAnnotations);
await this._cleanupAndRedrawAnnotations(currentPageAnnotations, annotation => annotation.pageNumber === page);
}
private _deleteAnnotations(annotationsToDelete?: AnnotationWrapper[]) {
if (!annotationsToDelete) {
this._instance.Core.annotationManager.deleteAnnotations(this._instance.Core.annotationManager.getAnnotationsList(), {
imported: true,
force: true,
});
}
annotationsToDelete?.forEach(annotation => {
this._findAndDeleteAnnotation(annotation.id);
});
}
private async _cleanupAndRedrawAnnotations(
annotationsToDelete?: AnnotationWrapper[],
currentAnnotations?: AnnotationWrapper[],
newAnnotationsFilter?: (annotation: AnnotationWrapper) => boolean,
) {
this.rebuildFilters();
if (this.viewModeService.viewMode === 'STANDARD') {
const startTime = new Date().getTime();
annotationsToDelete?.forEach(annotation => {
this._findAndDeleteAnnotation(annotation.id);
});
const newAnnotations = newAnnotationsFilter ? this.allAnnotations.filter(newAnnotationsFilter) : this.allAnnotations;
this._handleDeltaAnnotationFilters(annotationsToDelete ?? [], newAnnotations);
const newAnnotations = newAnnotationsFilter ? this.visibleAnnotations.filter(newAnnotationsFilter) : this.visibleAnnotations;
this._handleDeltaAnnotationFilters(currentAnnotations ?? [], newAnnotations);
await this._redrawAnnotations(newAnnotations);
console.log(
`[REDACTION] Annotations redraw time: ${new Date().getTime() - startTime} ms for ${newAnnotations.length} annotations`,
@ -654,6 +664,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
const oldPageSpecificFilters = this._annotationProcessingService.getAnnotationFilter(currentPageAnnotations);
const newPageSpecificFilters = this._annotationProcessingService.getAnnotationFilter(newPageAnnotations);
handleFilterDelta(oldPageSpecificFilters, newPageSpecificFilters, primaryFilters);
this._filterService.addFilterGroup({
...primaryFilterGroup,

View File

@ -159,7 +159,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnDestroy,
ariaExpanded: this._excludedPagesService?.shown$,
showDot: !!this.file.excludedPages?.length,
icon: 'red:exclude-pages',
show: !!this._excludedPagesService,
show: !!this._excludedPagesService && !this.file.excluded,
},
{
type: ActionTypes.circleBtn,

View File

@ -19,5 +19,6 @@ export const processingFileStatusTranslations: { [key in ProcessingFileStatus]:
OCR_PROCESSING: _('file-status.ocr-processing'),
PROCESSING: _('file-status.processing'),
REPROCESS: _('file-status.reprocess'),
SURROUNDING_TEXT_PROCESSING: _('file-status.processing'),
UNPROCESSED: _('file-status.unprocessed'),
};

View File

@ -41,7 +41,7 @@ export class FileUploadService extends GenericService<IFileUploadResult> impleme
) {
super(_injector, 'upload');
const fileFetch$ = this._fetchFiles$.pipe(
throttleTime(1500),
throttleTime(250),
switchMap(dossierId => this._filesService.loadAll(dossierId)),
);
this._subscriptions.add(fileFetch$.subscribe());

View File

@ -2,7 +2,7 @@ import { Injectable, Injector } from '@angular/core';
import { GenericService, List, mapEach, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
import * as moment from 'moment';
import { TranslateService } from '@ngx-translate/core';
import { iif, Observable } from 'rxjs';
import { EMPTY, iif, Observable } from 'rxjs';
import { INotification, Notification, NotificationTypes } from '@red/domain';
import { map, switchMap } from 'rxjs/operators';
import { notificationsTranslations } from '../translations/notifications-translations';
@ -40,7 +40,7 @@ export class NotificationsService extends GenericService<Notification> {
@Validate()
getNotificationsIfChanged(@RequiredParam() includeSeen: boolean): Observable<Notification[]> {
return this.hasChanges$().pipe(switchMap(changed => iif(() => changed, this.getNotifications(includeSeen))));
return this.hasChanges$().pipe(switchMap(changed => iif(() => changed, this.getNotifications(includeSeen), EMPTY)));
}
@Validate()
@ -54,7 +54,7 @@ export class NotificationsService extends GenericService<Notification> {
}
private _new(notification: INotification) {
const message = this._translate(notification, notificationsTranslations[notification.notificationType]);
const message = this._translate(notification, notificationsTranslations[notification.notificationType] as string);
const time = this._getTime(notification.creationDate);
return new Notification(notification, message, time);
}
@ -64,7 +64,7 @@ export class NotificationsService extends GenericService<Notification> {
return moment(date).format('hh:mm A');
}
private _translate(notification: INotification, translation: string) {
private _translate(notification: INotification, translation: string): string {
const fileId = notification.target.fileId;
const dossierId = notification.target.dossierId;
const dossier = this._dossiersService.find(dossierId);

View File

@ -97,7 +97,7 @@ export class PermissionsService {
// TODO: Remove '?', after we make sure file is loaded before page
canPerformAnnotationActions(file: File): boolean {
return (file?.isUnderReview || file?.isUnderApproval) && this.isFileAssignee(file);
return !file.excluded && (file?.isUnderReview || file?.isUnderApproval) && this.isFileAssignee(file);
}
canUndoApproval(file: File | File[]): boolean {

View File

@ -160,6 +160,16 @@ export class AppStateService {
}
}
dictionaryData['dossier_redaction'] = new Dictionary(
{
hexColor: colors.manualRedactionColor || FALLBACK_COLOR,
type: 'dossier_redaction',
hint: false,
recommendation: false,
},
true,
);
dictionaryData['declined-suggestion'] = new Dictionary(
{
hexColor: colors.notRedacted || FALLBACK_COLOR,

View File

@ -3,7 +3,7 @@
"ADMIN_CONTACT_URL": null,
"API_URL": "https://aks-staging.iqser.cloud/redaction-gateway-v1",
"APP_NAME": "RedactManager",
"AUTO_READ_TIME": 1.5,
"AUTO_READ_TIME": 3,
"BACKEND_APP_VERSION": "4.4.40",
"DELETE_RETENTION_HOURS": 96,
"EULA_URL": "EULA_URL",

File diff suppressed because it is too large Load Diff

View File

@ -461,6 +461,12 @@
"deny-text": "Cancel Upload",
"question": "Please choose if <b>{fileName}</b> is a single or multi-file report template",
"title": "Report Template Upload"
},
"report-template-same-name": {
"confirmation-text": "Yes. Continue upload",
"deny-text": "No. Cancel Upload",
"question": "There is already a Report Template with the name: <b>{fileName}</b>. Do you wish to continue?",
"title": "Report Template Upload"
}
},
"content": "Reason",

@ -1 +1 @@
Subproject commit b234ac102015a300d775f8856947548d51385b97
Subproject commit 2e36f3cac77411c4cef0ec5b51165aa62a9d075c

View File

@ -15,6 +15,7 @@ export const ProcessingFileStatuses = {
ERROR: 'ERROR',
FULLREPROCESS: 'FULLREPROCESS',
IMAGE_ANALYZING: 'IMAGE_ANALYZING',
SURROUNDING_TEXT_PROCESSING: 'SURROUNDING_TEXT_PROCESSING',
INDEXING: 'INDEXING',
OCR_PROCESSING: 'OCR_PROCESSING',
PROCESSED: 'PROCESSED',
@ -28,6 +29,7 @@ export type ProcessingFileStatus = keyof typeof ProcessingFileStatuses;
export const isProcessingStatuses: List<ProcessingFileStatus> = [
ProcessingFileStatuses.REPROCESS,
ProcessingFileStatuses.FULLREPROCESS,
ProcessingFileStatuses.SURROUNDING_TEXT_PROCESSING,
ProcessingFileStatuses.OCR_PROCESSING,
ProcessingFileStatuses.IMAGE_ANALYZING,
ProcessingFileStatuses.INDEXING,

View File

@ -3,6 +3,7 @@ export const ReportStatuses = {
DELETED: 'DELETED',
ERROR: 'ERROR',
FULLREPROCESS: 'FULLREPROCESS',
SURROUNDING_TEXT_PROCESSING: 'SURROUNDING_TEXT_PROCESSING',
OCR_PROCESSING: 'OCR_PROCESSING',
PROCESSING: 'PROCESSING',
REPROCESS: 'REPROCESS',

View File

@ -1,6 +1,6 @@
{
"name": "redaction",
"version": "3.156.0",
"version": "3.163.0",
"private": true,
"license": "MIT",
"scripts": {
@ -23,25 +23,25 @@
}
},
"dependencies": {
"@angular/animations": "13.1.1",
"@angular/cdk": "13.1.1",
"@angular/common": "13.1.1",
"@angular/compiler": "13.1.1",
"@angular/core": "13.1.1",
"@angular/forms": "13.1.1",
"@angular/material": "13.1.1",
"@angular/material-moment-adapter": "^13.0.2",
"@angular/platform-browser": "13.1.1",
"@angular/platform-browser-dynamic": "13.1.1",
"@angular/router": "13.1.1",
"@angular/service-worker": "13.1.1",
"@angular/animations": "13.1.2",
"@angular/cdk": "13.1.2",
"@angular/common": "13.1.2",
"@angular/compiler": "13.1.2",
"@angular/core": "13.1.2",
"@angular/forms": "13.1.2",
"@angular/material": "13.1.2",
"@angular/material-moment-adapter": "^13.1.2",
"@angular/platform-browser": "13.1.2",
"@angular/platform-browser-dynamic": "13.1.2",
"@angular/router": "13.1.2",
"@angular/service-worker": "13.1.2",
"@biesbjerg/ngx-translate-extract-marker": "^1.0.0",
"@materia-ui/ngx-monaco-editor": "^6.0.0-beta.1",
"@materia-ui/ngx-monaco-editor": "^6.0.0",
"@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0",
"@nrwl/angular": "13.2.3",
"@nrwl/angular": "13.4.5",
"@pdftron/webviewer": "8.2.0",
"@swimlane/ngx-charts": "^17.0.1",
"@swimlane/ngx-charts": "^20.0.1",
"file-saver": "^2.0.5",
"jwt-decode": "^3.1.2",
"keycloak-angular": "^9.0.0",
@ -49,70 +49,71 @@
"lodash.orderby": "^4.6.0",
"messageformat": "^2.3.0",
"moment": "^2.29.1",
"monaco-editor": "^0.30.1",
"monaco-editor": "^0.31.1",
"ngx-color-picker": "^11.0.0",
"ngx-toastr": "^14.1.3",
"ngx-translate-messageformat-compiler": "^4.11.0",
"ngx-translate-messageformat-compiler": "^5.0.1",
"papaparse": "^5.3.1",
"rxjs": "~6.6.7",
"sass": "^1.39.2",
"rxjs": "~7.5.2",
"sass": "^1.48.0",
"scroll-into-view-if-needed": "^2.2.28",
"streamsaver": "^2.0.5",
"tslib": "^2.3.1",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "13.1.2",
"@angular-devkit/build-angular": "13.1.3",
"@angular-eslint/eslint-plugin": "13.0.1",
"@angular-eslint/eslint-plugin-template": "13.0.1",
"@angular-eslint/template-parser": "13.0.1",
"@angular/cli": "13.1.2",
"@angular/compiler-cli": "13.1.1",
"@angular/language-service": "13.1.1",
"@nrwl/cli": "13.2.3",
"@nrwl/cypress": "13.2.3",
"@nrwl/eslint-plugin-nx": "13.2.3",
"@nrwl/jest": "13.2.3",
"@nrwl/linter": "13.2.3",
"@nrwl/tao": "13.2.3",
"@nrwl/workspace": "13.2.3",
"@angular/cli": "13.1.3",
"@angular/compiler-cli": "13.1.2",
"@angular/language-service": "13.1.2",
"@bartholomej/ngx-translate-extract": "^8.0.2",
"@nrwl/cli": "13.4.5",
"@nrwl/cypress": "13.4.5",
"@nrwl/eslint-plugin-nx": "13.4.5",
"@nrwl/jest": "13.4.5",
"@nrwl/linter": "13.4.5",
"@nrwl/tao": "13.4.5",
"@nrwl/workspace": "13.4.5",
"@types/cypress": "^1.1.3",
"@types/jest": "27.0.3",
"@types/lodash": "^4.14.177",
"@types/node": "16.11.10",
"@typescript-eslint/eslint-plugin": "4.33.0",
"@typescript-eslint/parser": "4.33.0",
"@types/jest": "27.4.0",
"@types/lodash": "^4.14.178",
"@types/node": "17.0.9",
"@typescript-eslint/eslint-plugin": "5.9.1",
"@typescript-eslint/parser": "5.3.1",
"axios": "^0.24.0",
"@bartholomej/ngx-translate-extract": "^8.0.1",
"cypress": "^6.9.1",
"cypress-file-upload": "^5.0.8",
"cypress-keycloak": "^1.7.0",
"cypress-keycloak-commands": "^1.2.0",
"cypress-localstorage-commands": "^1.5.0",
"dotenv": "10.0.0",
"eslint": "7.32.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-airbnb-typescript": "^14.0.0",
"eslint": "8.7.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^16.1.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-import": "2.24.2",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-prettier": "^4.0.0",
"google-translate-api-browser": "^1.1.71",
"husky": "4.3.8",
"jest": "27.3.1",
"jest": "27.4.7",
"jest-preset-angular": "11.0.1",
"ng-packagr": "13.0.8",
"postcss": "^8.3.9",
"ng-packagr": "13.1.3",
"postcss": "^8.4.5",
"postcss-import": "^14.0.2",
"postcss-preset-env": "^7.0.1",
"postcss-preset-env": "^7.2.3",
"postcss-url": "^10.1.1",
"prettier": "2.5.0",
"pretty-quick": "^3.1.1",
"prettier": "2.5.1",
"pretty-quick": "^3.1.3",
"sonarqube-scanner": "^2.8.1",
"superagent": "^6.1.0",
"superagent": "^7.0.2",
"superagent-promise": "^1.1.0",
"ts-jest": "27.0.7",
"ts-jest": "27.1.3",
"ts-node": "10.4.0",
"typescript": "4.4.4",
"webpack": "^4.18.1"
"typescript": "4.5.4",
"webpack": "^4.18.1",
"xliff": "^6.0.0"
}
}

Binary file not shown.

View File

@ -1,6 +1,9 @@
import * as fs from 'fs';
import axios from 'axios';
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
// @ts-ignore
import * as xliff from 'xliff';
// import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
function flatten(data: any) {
const result: any = {};
@ -55,7 +58,7 @@ async function execute() {
const apiKey = 'AIzaSyBiqNTundSKFjAJnSb4wSVLDU6w0Kv651M';
const tmfc = new TranslateMessageFormatCompiler();
// const tmfc = new TranslateMessageFormatCompiler();
for (const key of Object.keys(flatEnglish)) {
if (!flatGerman[key]) {
@ -80,8 +83,8 @@ async function execute() {
for (let key of Object.keys(flatGerman)) {
try {
const result = tmfc.compile(flatGerman[key], 'de');
//console.log(result);
// const result = tmfc.compile(flatGerman[key], 'de');
// console.log(result);
} catch (e) {
console.error('ERROR AT: ', flatGerman[key]);
}
@ -89,8 +92,8 @@ async function execute() {
for (let key of Object.keys(flatEnglish)) {
try {
const result = tmfc.compile(flatEnglish[key], 'de');
console.log(result);
// const result = tmfc.compile(flatEnglish[key], 'de');
// console.log(result);
} catch (e) {
console.error('ERROR AT: ', flatEnglish[key]);
}
@ -101,6 +104,44 @@ async function execute() {
const finalGerman = unflatten(mergedGerman);
fs.writeFileSync('./../../apps/red-ui/src/assets/i18n/de.json', JSON.stringify(finalGerman));
const js: any = {
resources: {
redaction: {},
},
sourceLanguage: 'en-US',
targetLanguage: 'de-DE',
};
for (const key of Object.keys(flatEnglish)) {
js.resources.redaction[`${key}`] = {
source: flatEnglish[`${key}`],
target: flatGerman[`${key}`],
};
}
xliff.jsToXliff12(js, (err: any, res: any) => {
fs.writeFileSync('./redaction-en-to-de.xliff', res);
});
const xliffImport = fs.readFileSync('./import.xliff', 'utf-8');
xliff.xliff12ToJs(xliffImport, (err: any, res: any) => {
const ns = res.resources.redaction;
const importGerman: any = {};
const importEnglish: any = {};
for (let key of Object.keys(ns)) {
importGerman[key] = ns[key].target;
importEnglish[key] = ns[key].source;
}
const importReadyEnglish = unflatten(importEnglish);
const importReadyGerman = unflatten(importGerman);
console.log(importReadyEnglish);
console.log(importReadyGerman);
});
}
execute().then();

4127
tools/auto-i18n/import.xliff Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4295
tools/auto-i18n/test.xml Normal file

File diff suppressed because it is too large Load Diff

2706
yarn.lock

File diff suppressed because it is too large Load Diff