lint fix
This commit is contained in:
parent
7d2890af26
commit
8acaa88f34
@ -38,26 +38,28 @@
|
||||
<mat-icon svgIcon="red:expand"></mat-icon>
|
||||
{{ 'top-bar.navigation-items.back-to-projects' | translate }}
|
||||
</a>
|
||||
<mat-icon class="primary" *ngIf="!appStateService.activeProject && projectsView" svgIcon="red:arrow-down"></mat-icon>
|
||||
<mat-icon *ngIf="appStateService.activeProject" svgIcon="red:arrow-right"></mat-icon>
|
||||
<a
|
||||
*ngIf="appStateService.activeProject"
|
||||
class="breadcrumb"
|
||||
[routerLink]="'/ui/projects/' + appStateService.activeProjectId"
|
||||
routerLinkActive="active"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
>
|
||||
{{ appStateService.activeProject.project.projectName }}
|
||||
</a>
|
||||
<mat-icon svgIcon="red:arrow-right" *ngIf="appStateService.activeFile"></mat-icon>
|
||||
<a
|
||||
*ngIf="appStateService.activeFile"
|
||||
class="breadcrumb"
|
||||
[routerLink]="'/ui/projects/' + appStateService.activeProjectId + '/file/' + appStateService.activeFile.fileId"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ appStateService.activeFile.filename }}
|
||||
</a>
|
||||
<ng-container *ngIf="projectsView">
|
||||
<mat-icon class="primary" *ngIf="!appStateService.activeProject" svgIcon="red:arrow-down"></mat-icon>
|
||||
<mat-icon *ngIf="appStateService.activeProject" svgIcon="red:arrow-right"></mat-icon>
|
||||
<a
|
||||
*ngIf="appStateService.activeProject"
|
||||
class="breadcrumb"
|
||||
[routerLink]="'/ui/projects/' + appStateService.activeProjectId"
|
||||
routerLinkActive="active"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
>
|
||||
{{ appStateService.activeProject.project.projectName }}
|
||||
</a>
|
||||
<mat-icon svgIcon="red:arrow-right" *ngIf="appStateService.activeFile"></mat-icon>
|
||||
<a
|
||||
*ngIf="appStateService.activeFile"
|
||||
class="breadcrumb"
|
||||
[routerLink]="'/ui/projects/' + appStateService.activeProjectId + '/file/' + appStateService.activeFile.fileId"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ appStateService.activeFile.filename }}
|
||||
</a>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="center flex-1">
|
||||
<redaction-hidden-action (action)="userPreferenceService.toggleDevFeatures()">
|
||||
|
||||
@ -5,7 +5,7 @@ import { LanguageService } from '../../i18n/language.service';
|
||||
import { PermissionsService } from '../../common/service/permissions.service';
|
||||
import { UserPreferenceService } from '../../common/service/user-preference.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { AppConfigKey, AppConfigService } from '../../app-config/app-config.service';
|
||||
import { AppConfigService } from '../../app-config/app-config.service';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { FileDownloadService } from '../../upload-download/file-download.service';
|
||||
import { StatusOverlayService } from '../../upload-download/status-overlay.service';
|
||||
|
||||
@ -180,6 +180,7 @@ export class AnnotationWrapper {
|
||||
annotationWrapper.userId = redactionLogEntry.userId;
|
||||
AnnotationWrapper._createContent(annotationWrapper, redactionLogEntry);
|
||||
AnnotationWrapper._setSuperType(annotationWrapper, redactionLogEntry);
|
||||
AnnotationWrapper._handleSkippedState(annotationWrapper, redactionLogEntry);
|
||||
AnnotationWrapper._handleRecommendations(annotationWrapper, redactionLogEntry);
|
||||
annotationWrapper.typeLabel = 'annotation-type.' + annotationWrapper.superType;
|
||||
|
||||
@ -242,9 +243,18 @@ export class AnnotationWrapper {
|
||||
if (!annotationWrapper.superType) {
|
||||
annotationWrapper.superType = annotationWrapper.redaction ? 'redaction' : annotationWrapper.hint ? 'hint' : 'skipped';
|
||||
}
|
||||
}
|
||||
|
||||
private static _handleSkippedState(annotationWrapper: AnnotationWrapper, redactionLogEntryWrapper: RedactionLogEntryWrapper) {
|
||||
if (annotationWrapper.superType === 'skipped') {
|
||||
if (!annotationWrapper.userId && annotationWrapper.content.indexOf('manual override') > 0) {
|
||||
if (!annotationWrapper.userId) {
|
||||
if (redactionLogEntryWrapper.manualRedactionType === 'REMOVE' || redactionLogEntryWrapper.manualRedactionType === 'UNDO') {
|
||||
annotationWrapper.superType = 'pending-analysis';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (redactionLogEntryWrapper.actionPendingReanalysis) {
|
||||
annotationWrapper.superType = 'pending-analysis';
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +101,25 @@ export class FileDataModel {
|
||||
result.push(redactionLogEntryWrapper);
|
||||
});
|
||||
|
||||
this.manualRedactions.forceRedactions.forEach((forceRedaction) => {
|
||||
if (forceRedaction.status === 'DECLINED') {
|
||||
return;
|
||||
}
|
||||
|
||||
const relevantRedactionLogEntry = result.find((r) => r.id === forceRedaction.id);
|
||||
// an entry for this request already exists in the redactionLog
|
||||
if (!!relevantRedactionLogEntry) {
|
||||
relevantRedactionLogEntry.userId = forceRedaction.user;
|
||||
relevantRedactionLogEntry.dictionaryEntry = false;
|
||||
|
||||
// if statuses differ
|
||||
if (!forceRedaction.processedDate || forceRedaction.status !== relevantRedactionLogEntry.status) {
|
||||
relevantRedactionLogEntry.actionPendingReanalysis = true;
|
||||
relevantRedactionLogEntry.status = forceRedaction.status;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.manualRedactions.entriesToAdd.forEach((manual) => {
|
||||
const markedAsReasonRedactionLogEntry = result.find((r) => r.id === manual.reason);
|
||||
|
||||
@ -200,7 +219,7 @@ export class FileDataModel {
|
||||
// REMOVE has been undone - not yet processed
|
||||
if (!foundManualEntry) {
|
||||
redactionLogEntry.manual = false;
|
||||
redactionLogEntry.manualRedactionType = null;
|
||||
redactionLogEntry.manualRedactionType = 'UNDO';
|
||||
redactionLogEntry.status = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ export interface RedactionLogEntryWrapper {
|
||||
id?: string;
|
||||
legalBasis?: string;
|
||||
manual?: boolean;
|
||||
manualRedactionType?: 'ADD' | 'REMOVE';
|
||||
manualRedactionType?: 'ADD' | 'REMOVE' | 'UNDO';
|
||||
matchedRule?: number;
|
||||
positions?: Array<Rectangle>;
|
||||
reason?: string;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ApplicationRef, Injectable } from '@angular/core';
|
||||
import { DownloadControllerService, FileManagementControllerService } from '@redaction/red-ui-http';
|
||||
import { interval, Observable } from 'rxjs';
|
||||
import { AppConfigService } from '../app-config/app-config.service';
|
||||
import { AppConfigKey, AppConfigService } from '../app-config/app-config.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DialogService } from '../dialogs/dialog.service';
|
||||
import { ProjectWrapper } from '../state/model/project.wrapper';
|
||||
@ -10,7 +10,7 @@ import { mergeMap, tap } from 'rxjs/operators';
|
||||
import { DownloadStatusWrapper } from './model/download-status.wrapper';
|
||||
import { AppStateService } from '../state/app-state.service';
|
||||
import { PermissionsService } from '../common/service/permissions.service';
|
||||
import { StreamDownloadService } from '../utils/stream-download.service';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -27,9 +27,9 @@ export class FileDownloadService {
|
||||
private readonly _downloadControllerService: DownloadControllerService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _appConfigService: AppConfigService,
|
||||
private readonly _keycloakService: KeycloakService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
private readonly _dialogService: DialogService,
|
||||
private readonly _streamDownloadService: StreamDownloadService
|
||||
private readonly _dialogService: DialogService
|
||||
) {
|
||||
interval(5000).subscribe((val) => {
|
||||
if (_permissionsService.isUser()) {
|
||||
@ -43,8 +43,8 @@ export class FileDownloadService {
|
||||
.prepareDownload({
|
||||
fileIds: fileStatusWrappers.map((f) => f.fileId),
|
||||
projectId: project.projectId,
|
||||
reportTypes: ['SINGLE_FILE_EFSA_TEMPLATE', 'SINGLE_FILE_SYNGENTA_TEMPLATE'],
|
||||
downloadFileTypes: ['PREVIEW', 'REDACTED', 'FLATTEN']
|
||||
reportTypes: ['WORD_SINGLE_FILE_EFSA_TEMPLATE', 'WORD_SINGLE_FILE_SYNGENTA_TEMPLATE', 'EXCEL_MULTI_FILE'],
|
||||
downloadFileTypes: ['PREVIEW', 'REDACTED']
|
||||
})
|
||||
.pipe(
|
||||
mergeMap(() => {
|
||||
@ -62,7 +62,20 @@ export class FileDownloadService {
|
||||
);
|
||||
}
|
||||
|
||||
public performDownload(status: DownloadStatusWrapper) {
|
||||
this._streamDownloadService.performDownload(status);
|
||||
public async performDownload(status: DownloadStatusWrapper) {
|
||||
const token = await this._keycloakService.getToken();
|
||||
const anchor = document.createElement('a');
|
||||
anchor.href =
|
||||
this._appConfigService.getConfig(AppConfigKey.API_URL) +
|
||||
'/async/download?access_token=' +
|
||||
encodeURIComponent(token) +
|
||||
'&storageId=' +
|
||||
encodeURIComponent(status.storageId);
|
||||
anchor.download = status.filename;
|
||||
anchor.target = '_blank';
|
||||
|
||||
document.body.appendChild(anchor);
|
||||
anchor.click();
|
||||
document.body.removeChild(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,100 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import streamSaver from 'streamsaver';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AppConfigKey, AppConfigService } from '../app-config/app-config.service';
|
||||
import { DownloadStatusWrapper } from '../upload-download/model/download-status.wrapper';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { NotificationService, NotificationType } from '../notification/notification.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class StreamDownloadService {
|
||||
private _activeDownloadCount = 0;
|
||||
|
||||
constructor(
|
||||
private readonly _appConfigService: AppConfigService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _keyCloakService: KeycloakService,
|
||||
private readonly _translateService: TranslateService
|
||||
) {
|
||||
streamSaver.mitm = '/assets/stream-saver/mitm.html';
|
||||
}
|
||||
|
||||
async performDownload(downloadStatusWrapper: DownloadStatusWrapper) {
|
||||
this._activeDownloadCount += 1;
|
||||
const token = await this._keyCloakService.getToken();
|
||||
fetch(this._appConfigService.getConfig(AppConfigKey.API_URL) + '/async/download/get', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'bearer ' + token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
storageId: downloadStatusWrapper.storageId
|
||||
})
|
||||
})
|
||||
.then((response) => {
|
||||
// These code section is adapted from an example of the StreamSaver.js
|
||||
// https://jimmywarting.github.io/StreamSaver.js/examples/fetch.html
|
||||
|
||||
// If the WritableStream is not available (Firefox, Safari), take it from the ponyfill
|
||||
if (!window.WritableStream) {
|
||||
streamSaver.WritableStream = WritableStream;
|
||||
window.WritableStream = WritableStream;
|
||||
}
|
||||
|
||||
const fileStream = streamSaver.createWriteStream(downloadStatusWrapper.filename);
|
||||
const readableStream = response.body;
|
||||
|
||||
// More optimized
|
||||
if (readableStream.pipeTo) {
|
||||
return readableStream.pipeTo(fileStream);
|
||||
}
|
||||
|
||||
const writer = fileStream.getWriter();
|
||||
this._registerUnload(writer);
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const pump = () => reader.read().then((res) => (res.done ? this._finalizeWriter(writer) : writer.write(res.value).then(pump)));
|
||||
|
||||
pump();
|
||||
})
|
||||
.catch(() => {
|
||||
this._notificationService.showToastNotification(
|
||||
this._translateService.instant('stream-download.error', downloadStatusWrapper),
|
||||
null,
|
||||
NotificationType.ERROR
|
||||
);
|
||||
this._decrementDownloadCnt();
|
||||
});
|
||||
}
|
||||
|
||||
private _finalizeWriter(writer) {
|
||||
writer.close();
|
||||
this._decrementDownloadCnt();
|
||||
}
|
||||
|
||||
private _decrementDownloadCnt() {
|
||||
this._activeDownloadCount -= 1;
|
||||
if (this._activeDownloadCount <= 0) {
|
||||
window.onunload = () => {};
|
||||
window.onbeforeunload = () => {};
|
||||
}
|
||||
}
|
||||
|
||||
private _registerUnload(writer) {
|
||||
window.onunload = () => {
|
||||
streamSaver.WritableStream.abort();
|
||||
// also possible to call abort on the writer you got from `getWriter()`
|
||||
writer.abort();
|
||||
};
|
||||
|
||||
window.onbeforeunload = (evt) => {
|
||||
if (this._activeDownloadCount > 0) {
|
||||
return this._translateService.instant('stream-download.abort');
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,30 +1,25 @@
|
||||
import { AfterViewChecked, AfterViewInit, Directive, ElementRef, HostListener, Input } from '@angular/core';
|
||||
import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnDestroy } from '@angular/core';
|
||||
import { debounce } from './debounce';
|
||||
|
||||
@Directive({
|
||||
selector: '[redactionSyncWidth]',
|
||||
exportAs: 'redactionSyncWidth'
|
||||
})
|
||||
export class SyncWidthDirective implements AfterViewInit {
|
||||
export class SyncWidthDirective implements AfterViewInit, OnDestroy {
|
||||
@Input()
|
||||
redactionSyncWidth: string;
|
||||
private _interval: number;
|
||||
|
||||
constructor(private el: ElementRef) {}
|
||||
|
||||
private get _sampleRow(): { tableRow: Element; length: number } {
|
||||
const tableRows = document.getElementsByClassName(this.redactionSyncWidth);
|
||||
let length = 0;
|
||||
let tableRow: Element;
|
||||
ngAfterViewInit(): void {
|
||||
this._interval = setInterval(() => {
|
||||
this.matchWidth();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
for (let idx = 0; idx < tableRows.length; ++idx) {
|
||||
const row = tableRows.item(idx);
|
||||
if (row.children.length > length) {
|
||||
length = row.children.length;
|
||||
tableRow = row;
|
||||
}
|
||||
}
|
||||
|
||||
return { tableRow, length };
|
||||
ngOnDestroy(): void {
|
||||
clearInterval(this._interval);
|
||||
}
|
||||
|
||||
@debounce(10)
|
||||
@ -55,7 +50,19 @@ export class SyncWidthDirective implements AfterViewInit {
|
||||
this.matchWidth();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.matchWidth();
|
||||
private get _sampleRow(): { tableRow: Element; length: number } {
|
||||
const tableRows = document.getElementsByClassName(this.redactionSyncWidth);
|
||||
let length = 0;
|
||||
let tableRow: Element;
|
||||
|
||||
for (let idx = 0; idx < tableRows.length; ++idx) {
|
||||
const row = tableRows.item(idx);
|
||||
if (row.children.length > length) {
|
||||
length = row.children.length;
|
||||
tableRow = row;
|
||||
}
|
||||
}
|
||||
|
||||
return { tableRow, length };
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,8 +15,6 @@ import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@a
|
||||
import { CustomHttpUrlEncodingCodec } from '../encoder';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { DownloadRequest } from '../model/downloadRequest';
|
||||
import { DownloadResponse } from '../model/downloadResponse';
|
||||
import { DownloadStatusResponse } from '../model/downloadStatusResponse';
|
||||
import { PrepareDownloadRequest } from '../model/prepareDownloadRequest';
|
||||
@ -57,20 +55,22 @@ export class DownloadControllerService {
|
||||
/**
|
||||
* Returns a downloadable byte stream of the requested file
|
||||
* Use the optional \"inline\" request parameter to select, if this report will be opened in the browser.
|
||||
* @param body downloadRequest
|
||||
* @param storageId storageId
|
||||
* @param inline inline
|
||||
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
|
||||
* @param reportProgress flag to report request and response progress.
|
||||
*/
|
||||
public downloadFile(body: DownloadRequest, inline?: boolean, observe?: 'body', reportProgress?: boolean): Observable<any>;
|
||||
public downloadFile(body: DownloadRequest, inline?: boolean, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
|
||||
public downloadFile(body: DownloadRequest, inline?: boolean, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
|
||||
public downloadFile(body: DownloadRequest, inline?: boolean, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
|
||||
if (body === null || body === undefined) {
|
||||
throw new Error('Required parameter body was null or undefined when calling downloadFile.');
|
||||
public downloadFile(storageId: string, inline?: boolean, observe?: 'body', reportProgress?: boolean): Observable<any>;
|
||||
public downloadFile(storageId: string, inline?: boolean, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
|
||||
public downloadFile(storageId: string, inline?: boolean, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
|
||||
public downloadFile(storageId: string, inline?: boolean, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
|
||||
if (storageId === null || storageId === undefined) {
|
||||
throw new Error('Required parameter storageId was null or undefined when calling downloadFile.');
|
||||
}
|
||||
|
||||
let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() });
|
||||
queryParameters = queryParameters.set('storageId', <any>storageId);
|
||||
|
||||
if (inline !== undefined && inline !== null) {
|
||||
queryParameters = queryParameters.set('inline', <any>inline);
|
||||
}
|
||||
@ -91,15 +91,9 @@ export class DownloadControllerService {
|
||||
}
|
||||
|
||||
// to determine the Content-Type header
|
||||
const consumes: string[] = ['application/json'];
|
||||
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
|
||||
if (httpContentTypeSelected !== undefined) {
|
||||
headers = headers.set('Content-Type', httpContentTypeSelected);
|
||||
}
|
||||
const consumes: string[] = [];
|
||||
|
||||
return this.httpClient.request('post', `${this.basePath}/async/download/get`, {
|
||||
responseType: 'blob',
|
||||
body: body,
|
||||
return this.httpClient.request<any>('get', `${this.basePath}/async/download`, {
|
||||
params: queryParameters,
|
||||
withCredentials: this.configuration.withCredentials,
|
||||
headers: headers,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user