Merge branch 'master' into VM/HelpModeUpdates

This commit is contained in:
Valentin 2021-08-16 11:13:23 +03:00
commit ef2f2caa2d
27 changed files with 481 additions and 80 deletions

View File

@ -1,2 +1,2 @@
<router-outlet></router-outlet>
<redaction-full-page-loading-indicator [displayed]="loadingService.isLoading$ | async"></redaction-full-page-loading-indicator>
<redaction-full-page-loading-indicator></redaction-full-page-loading-indicator>

View File

@ -5,6 +5,7 @@ import { DownloadControllerService } from '@redaction/red-ui-http';
import { CircleButtonTypes, DefaultListingServices, ListingComponent, TableColumnConfig } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { LoadingService } from '@services/loading.service';
import { timer } from 'rxjs';
@Component({
selector: 'redaction-downloads-list-screen',
@ -35,6 +36,9 @@ export class DownloadsListScreenComponent extends ListingComponent<DownloadStatu
async ngOnInit() {
this._loadingService.loadWhile(this._loadData());
this.addSubscription = timer(0, 5000).subscribe(async () => {
await this._loadData();
});
}
downloadItem(download: DownloadStatusWrapper) {

View File

@ -74,7 +74,7 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
hardDelete(dossiers = this.entitiesService.selected) {
const data = new ConfirmationDialogInput({
title: dossiers.length > 1 ? _('confirmation-dialog.delete-dossier.title-alt') : _('confirmation-dialog.delete-dossier.title'),
title: _('confirmation-dialog.delete-dossier.title'),
titleColor: TitleColors.PRIMARY,
question: _('confirmation-dialog.delete-dossier.question'),
// details: _('confirmation-dialog.delete-dossier.details'),
@ -83,7 +83,7 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
denyText: _('confirmation-dialog.delete-dossier.deny-text'),
translateParams: {
dossierName: dossiers[0].dossierName,
period: this._deleteRetentionHours
dossiersCount: dossiers.length
}
});
this._adminDialogService.openDialog('confirm', null, data, async () => {

View File

@ -1,6 +1,6 @@
<div *ngFor="let comment of annotation.comments" class="comment">
<div class="comment-details-wrapper">
<div [matTooltipPosition]="'above'" [matTooltip]="comment.date | date: 'exactCommentDate'" class="small-label">
<div [matTooltipPosition]="'above'" [matTooltip]="comment.date | date: 'exactDate'" class="small-label">
<b> {{ getOwnerName(comment) }} </b>
{{ comment.date | date: 'commentDate' }}
</div>

View File

@ -38,7 +38,7 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
get changed() {
for (const attr of this.attributes) {
if (this.isDate(attr)) {
if (this.isDate(attr) && attr.value) {
if (!moment(attr.value).isSame(moment(this.currentAttrValue(attr)))) {
return true;
}

View File

@ -0,0 +1,76 @@
<iqser-table-header
[bulkActions]="bulkActions"
[selectionEnabled]="true"
[tableColumnConfigs]="tableColumnConfigs"
[tableHeaderLabel]="tableHeaderLabel"
>
<div
[translateParams]="{ hours: deleteRetentionHours }"
[translate]="'edit-dossier-dialog.deleted-documents.instructions'"
class="instructions"
></div>
</iqser-table-header>
<redaction-empty-state
*ngIf="entitiesService.noData$ | async"
[text]="'edit-dossier-dialog.deleted-documents.no-data.title' | translate"
icon="red:document"
></redaction-empty-state>
<cdk-virtual-scroll-viewport *ngIf="(entitiesService.noData$ | async) === false" [itemSize]="itemSize" redactionHasScrollbar>
<div *cdkVirtualFor="let file of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey" class="table-item">
<div (click)="toggleEntitySelected($event, file)" class="selection-column">
<iqser-round-checkbox [active]="isSelected(file)"></iqser-round-checkbox>
</div>
<div class="filename">
<span>{{ file.filename }}</span>
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
{{ file.numberOfPages }}
</div>
</div>
<div class="small-label">{{ file.softDeleted | date: 'exactDate' }}</div>
<div>
<div class="small-label">{{ file.restoreDate | date: 'timeFromNow' }}</div>
<div class="action-buttons">
<iqser-circle-button
(action)="restore([file])"
*ngIf="file.canRestore"
[tooltip]="'edit-dossier-dialog.deleted-documents.action.restore' | translate"
[type]="circleButtonTypes.dark"
icon="red:put-back"
></iqser-circle-button>
<iqser-circle-button
(action)="hardDelete([file])"
[tooltip]="'edit-dossier-dialog.deleted-documents.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</div>
<div class="scrollbar-placeholder"></div>
</div>
</cdk-virtual-scroll-viewport>
<ng-template #bulkActions>
<div class="bulk-actions">
<iqser-circle-button
(action)="restore()"
*ngIf="canRestoreSelected$ | async"
[tooltip]="'edit-dossier-dialog.deleted-documents.bulk.restore' | translate"
[type]="circleButtonTypes.dark"
icon="red:put-back"
></iqser-circle-button>
<iqser-circle-button
(action)="hardDelete()"
*ngIf="entitiesService.areSomeSelected$ | async"
[tooltip]="'edit-dossier-dialog.deleted-documents.bulk.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</ng-template>

View File

@ -0,0 +1,41 @@
@import '../../../../../../assets/styles/variables';
@import '../../../../../../assets/styles/red-mixins';
.instructions {
color: $grey-7;
flex: 1;
text-align: end;
}
cdk-virtual-scroll-viewport {
height: calc(100% - 81px);
::ng-deep.cdk-virtual-scroll-content-wrapper {
grid-template-columns: auto 3fr 1fr 2fr 2fr 11px;
.table-item > div {
height: 50px;
&.filename span {
@include line-clamp(1);
}
&.stats-subtitle > div {
width: fit-content;
}
}
}
&.has-scrollbar:hover ::ng-deep.cdk-virtual-scroll-content-wrapper {
grid-template-columns: auto 3fr 1fr 2fr 2fr;
}
}
.bulk-actions {
display: flex;
align-items: center;
> *:not(:last-child) {
margin-right: 2px;
}
}

View File

@ -0,0 +1,141 @@
import { Component, EventEmitter, Injector, Input, OnInit, Output } from '@angular/core';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { DossierWrapper } from '@state/model/dossier.wrapper';
import { CircleButtonTypes, DefaultListingServices, ListingComponent, TableColumnConfig } from '@iqser/common-ui';
import { FileManagementControllerService, FileStatus, StatusControllerService } from '@redaction/red-ui-http';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { LoadingService } from '@services/loading.service';
import * as moment from 'moment';
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
import { getLeftDateTime } from '@utils/functions';
import { Observable } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { ConfirmationDialogInput, TitleColors } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { AppStateService } from '@state/app-state.service';
interface FileListItem extends FileStatus {
readonly canRestore: boolean;
readonly restoreDate: string;
}
@Component({
selector: 'redaction-edit-dossier-deleted-documents',
templateUrl: './edit-dossier-deleted-documents.component.html',
styleUrls: ['./edit-dossier-deleted-documents.component.scss'],
providers: [...DefaultListingServices]
})
export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileListItem> implements EditDossierSectionInterface, OnInit {
@Input() dossierWrapper: DossierWrapper;
@Output() updateDossier = new EventEmitter<any>();
readonly changed = false;
readonly canRestoreSelected$ = this._canRestoreSelected$;
disabled: boolean;
readonly tableColumnConfigs: TableColumnConfig<FileListItem>[] = [
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.name') },
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.pages') },
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.deleted-on') },
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.time-to-restore') }
];
readonly tableHeaderLabel = _('edit-dossier-dialog.deleted-documents.table-header.label');
readonly itemSize = 50;
readonly circleButtonTypes = CircleButtonTypes;
readonly deleteRetentionHours = this._appConfigService.getConfig(AppConfigKey.DELETE_RETENTION_HOURS);
protected readonly _primaryKey = 'fileId';
constructor(
protected readonly _injector: Injector,
private readonly _statusController: StatusControllerService,
private readonly _fileManagementController: FileManagementControllerService,
private readonly _appStateService: AppStateService,
private readonly _loadingService: LoadingService,
private readonly _appConfigService: AppConfigService,
private readonly _dialogService: DossiersDialogService
) {
super(_injector);
}
private get _canRestoreSelected$(): Observable<boolean> {
return this.entitiesService.selected$.pipe(
map(entities => entities.length && !entities.find(file => !file.canRestore)),
distinctUntilChanged()
);
}
hardDelete(files = this.entitiesService.selected) {
const data = new ConfirmationDialogInput({
title: _('confirmation-dialog.permanently-delete-file.title'),
titleColor: TitleColors.PRIMARY,
question: _('confirmation-dialog.permanently-delete-file.question'),
confirmationText: _('confirmation-dialog.permanently-delete-file.confirmation-text'),
requireInput: true,
denyText: _('confirmation-dialog.permanently-delete-file.deny-text'),
translateParams: {
fileName: files[0].filename,
filesCount: files.length
}
});
this._dialogService.openDialog('confirm', null, data, async () => {
this._loadingService.loadWhile(this._hardDelete(files));
});
}
async ngOnInit() {
this._loadingService.start();
const files = await this._statusController.getDeletedFileStatus(this.dossierWrapper.dossierId).toPromise();
this.entitiesService.setEntities(this._toListItems(files));
this._loadingService.stop();
}
revert() {}
save() {}
restore(files = this.entitiesService.selected) {
this._loadingService.loadWhile(this._restore(files));
}
private async _restore(files: FileListItem[]): Promise<void> {
const fileIds = files.map(f => f.fileId);
await this._fileManagementController.restoreFiles(fileIds, this.dossierWrapper.dossierId).toPromise();
this._removeFromList(fileIds);
await this._appStateService.reloadActiveDossierFiles();
this.updateDossier.emit();
}
private async _hardDelete(files: FileListItem[]) {
const fileIds = files.map(f => f.fileId);
await this._fileManagementController.hardDeleteFile(this.dossierWrapper.dossierId, fileIds).toPromise();
this._removeFromList(fileIds);
this.updateDossier.emit();
}
private _removeFromList(ids: string[]): void {
const entities = this.entitiesService.all.filter(e => !ids.includes(e.fileId));
this.entitiesService.setEntities(entities);
this.entitiesService.setSelected([]);
}
private _toListItems(files: FileStatus[]): FileListItem[] {
return files.map(file => this._toListItem(file));
}
private _toListItem(file: FileStatus): FileListItem {
const restoreDate = this._getRestoreDate(file.softDeleted);
return {
...file,
restoreDate,
canRestore: this._canRestoreFile(restoreDate)
};
}
private _canRestoreFile(restoreDate: string): boolean {
const { daysLeft, hoursLeft, minutesLeft } = getLeftDateTime(restoreDate);
return daysLeft >= 0 && hoursLeft >= 0 && minutesLeft > 0;
}
private _getRestoreDate(softDeletedTime: string): string {
return moment(softDeletedTime).add(this.deleteRetentionHours, 'hours').toISOString();
}
}

View File

@ -14,7 +14,7 @@
></div>
</redaction-side-nav>
<div>
<div [class.no-padding]="noPaddingTab" class="content">
<div [class.no-actions]="!showActionButtons" [class.no-padding]="noPaddingTab" class="content">
<div *ngIf="showHeading" class="heading">
{{ activeNavItem.title | translate }}
@ -58,9 +58,15 @@
*ngIf="activeNav === 'dossierAttributes'"
[dossierWrapper]="dossierWrapper"
></redaction-edit-dossier-attributes>
<redaction-edit-dossier-deleted-documents
(updateDossier)="updatedDossier($event)"
*ngIf="activeNav === 'deletedDocuments'"
[dossierWrapper]="dossierWrapper"
></redaction-edit-dossier-deleted-documents>
</div>
<div class="dialog-actions">
<div *ngIf="showActionButtons" class="dialog-actions">
<button
(click)="save()"
[disabled]="activeComponent?.disabled || !activeComponent?.changed"

View File

@ -22,6 +22,10 @@
padding: 0;
}
&.no-actions {
height: 100%;
}
::ng-deep .heading {
margin-bottom: 24px;
}

View File

@ -10,15 +10,16 @@ import { EditDossierTeamMembersComponent } from './team-members/edit-dossier-tea
import { EditDossierAttributesComponent } from './attributes/edit-dossier-attributes.component';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { EditDossierDeletedDocumentsComponent } from './deleted-documents/edit-dossier-deleted-documents.component';
type Section = 'dossierInfo' | 'downloadPackage' | 'dossierDictionary' | 'members' | 'dossierAttributes';
type Section = 'dossierInfo' | 'downloadPackage' | 'dossierDictionary' | 'members' | 'dossierAttributes' | 'deletedDocuments';
@Component({
templateUrl: './edit-dossier-dialog.component.html',
styleUrls: ['./edit-dossier-dialog.component.scss']
})
export class EditDossierDialogComponent {
readonly navItems: { key: Section; title: string; sideNavTitle?: string }[];
readonly navItems: { key: Section; title?: string; sideNavTitle?: string }[];
activeNav: Section;
dossierWrapper: DossierWrapper;
@ -27,6 +28,7 @@ export class EditDossierDialogComponent {
@ViewChild(EditDossierDictionaryComponent) dictionaryComponent: EditDossierDictionaryComponent;
@ViewChild(EditDossierTeamMembersComponent) membersComponent: EditDossierTeamMembersComponent;
@ViewChild(EditDossierAttributesComponent) attributesComponent: EditDossierAttributesComponent;
@ViewChild(EditDossierDeletedDocumentsComponent) deletedDocumentsComponent: EditDossierDeletedDocumentsComponent;
constructor(
private readonly _toaster: Toaster,
@ -62,6 +64,10 @@ export class EditDossierDialogComponent {
{
key: 'dossierAttributes',
title: _('edit-dossier-dialog.nav-items.dossier-attributes')
},
{
key: 'deletedDocuments',
sideNavTitle: _('edit-dossier-dialog.nav-items.deleted-documents')
}
];
@ -79,22 +85,27 @@ export class EditDossierDialogComponent {
downloadPackage: this.downloadPackageComponent,
dossierDictionary: this.dictionaryComponent,
members: this.membersComponent,
dossierAttributes: this.attributesComponent
dossierAttributes: this.attributesComponent,
deletedDocuments: this.deletedDocumentsComponent
}[this.activeNav];
}
get noPaddingTab(): boolean {
return ['dossierAttributes'].includes(this.activeNav);
return ['dossierAttributes', 'deletedDocuments'].includes(this.activeNav);
}
get showHeading(): boolean {
return !['dossierAttributes'].includes(this.activeNav);
return !['dossierAttributes', 'deletedDocuments'].includes(this.activeNav);
}
get showSubtitle(): boolean {
return ['dossierDictionary'].includes(this.activeNav);
}
get showActionButtons(): boolean {
return !['deletedDocuments'].includes(this.activeNav);
}
updatedDossier(updatedDossier: DossierWrapper) {
this._toaster.success(_('edit-dossier-dialog.change-successful'));

View File

@ -50,6 +50,7 @@ import { EditDossierAttributesComponent } from './dialogs/edit-dossier-dialog/at
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';
const screens = [DossierListingScreenComponent, DossierOverviewScreenComponent, FilePreviewScreenComponent, SearchScreenComponent];
@ -91,6 +92,7 @@ const components = [
ScrollButtonComponent,
PageExclusionComponent,
DossierDetailsStatsComponent,
EditDossierDeletedDocumentsComponent,
...screens,
...dialogs

View File

@ -131,7 +131,21 @@ export class AnnotationActionsService {
permissions: AnnotationPermissions.forUser(this._permissionsService.isApprover(), this._userService.currentUser, annotation)
}));
const canRecategorizeImage = annotations.length === 1 && annotationPermissions[0].permissions.canRecategorizeImage;
const canChangeLegalBasis = annotationPermissions.reduce((acc, next) => acc && next.permissions.canChangeLegalBasis, true);
if (canChangeLegalBasis) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/edit.svg'),
title: this._translateService.instant('annotation-actions.edit-reason.label'),
onClick: () => {
this._ngZone.run(() => {
this.changeLegalBasis(null, annotations, annotationsChanged);
});
}
});
}
const canRecategorizeImage = annotationPermissions.reduce((acc, next) => acc && next.permissions.canRecategorizeImage, true);
if (canRecategorizeImage) {
availableActions.push({
type: 'actionButton',

View File

@ -3,6 +3,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
export const fileStatusTranslations: { [key in FileStatus.StatusEnum]: string } = {
APPROVED: _('file-status.approved'),
DELETED: _('file-status.deleted'),
ERROR: _('file-status.error'),
EXCLUDED: _('file-status.excluded'),
FULLREPROCESS: _('file-status.full-reprocess'),

View File

@ -1,5 +1,7 @@
<section *ngIf="displayed" class="full-page-load-section"></section>
<section *ngIf="displayed" class="full-page-load-spinner">
<mat-spinner diameter="40"></mat-spinner>
<ng-content></ng-content>
</section>
<ng-container *ngIf="loadingService.isLoading$ | async">
<section class="full-page-load-section"></section>
<section class="full-page-load-spinner">
<mat-spinner diameter="40"></mat-spinner>
<ng-content></ng-content>
</section>
</ng-container>

View File

@ -1,4 +1,5 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { LoadingService } from '@services/loading.service';
@Component({
selector: 'redaction-full-page-loading-indicator',
@ -7,5 +8,5 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FullPageLoadingIndicatorComponent {
@Input() displayed = false;
constructor(readonly loadingService: LoadingService) {}
}

View File

@ -38,7 +38,7 @@ export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChange
}
get disabled(): boolean {
return !this.user?.isActive;
return this.user && !this.user?.isActive;
}
private get _colorClass() {

View File

@ -48,8 +48,7 @@ export class ConfirmationDialogComponent {
) {
this.config = _confirmationDialogInput ?? new ConfirmationDialogInput();
this.config = this.translate(this.config);
this.inputLabel =
this._translateService.instant('confirmation-dialog.delete-dossier.input-label') + ` '${this.config.confirmationText}'`;
this.inputLabel = this._translateService.instant('confirmation-dialog.input-label') + ` '${this.config.confirmationText}'`;
}
get isDeleteAction() {

View File

@ -33,7 +33,7 @@ export class DatePipe extends BaseDatePipe implements PipeTransform {
transform(value: any, format?: string, timezone?: string, locale?: string): string {
if (format === 'timeFromNow') return this._getTimeFromNow(value);
if (format === 'commentDate') return this._getCommentDate(value);
if (format === 'exactCommentDate') return this._getExactCommentDate(value);
if (format === 'exactDate') return this._getExactDate(value);
return super.transform(value, format, timezone, locale);
}
@ -87,15 +87,15 @@ export class DatePipe extends BaseDatePipe implements PipeTransform {
return year;
}
private _getExactCommentDate(item: string) {
private _getExactDate(item: string) {
const date = moment(item);
const day = date.date();
const month = this._translateService.instant(MONTH_NAMES[date.month()]);
const year = date.year();
const hour = date.hour();
const minute = date.minute();
const hour = date.hour().toString(10).padStart(2, '0');
const minute = date.minute().toString(10).padStart(2, '0');
return this._translateService.instant('exact-comment-date', {
return this._translateService.instant('exact-date', {
day,
month,
year,

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { BehaviorSubject } from 'rxjs';
const MIN_LOADING_TIME = 300;
@ -7,16 +7,15 @@ const MIN_LOADING_TIME = 300;
providedIn: 'root'
})
export class LoadingService {
private readonly _loadingEvent = new BehaviorSubject(false);
private readonly _loadingEvent$ = new BehaviorSubject(false);
readonly isLoading$ = this._loadingEvent$.asObservable();
private _loadingStarted: number;
get isLoading$(): Observable<boolean> {
return this._loadingEvent.asObservable();
}
start(): void {
this._loadingEvent.next(true);
this._loadingStarted = new Date().getTime();
setTimeout(() => {
this._loadingEvent$.next(true);
this._loadingStarted = new Date().getTime();
});
}
stop(): void {
@ -36,7 +35,7 @@ export class LoadingService {
}
private _stop() {
setTimeout(() => this._loadingEvent.next(false));
setTimeout(() => this._loadingEvent$.next(false));
}
private _stopAfter(timeout: number) {

View File

@ -1239,7 +1239,7 @@
"no-time-left": ""
},
"yesterday": "",
"exact-comment-date": "",
"exact-date": "",
"months": {
"jan": "",
"feb": "",

View File

@ -365,16 +365,21 @@
"title": "Compare with file: {fileName}"
},
"delete-dossier": {
"confirmation-text": "Delete Dossier",
"deny-text": "Keep Dossier",
"input-label": "To proceed please type below",
"question": "Are you sure you want to delete this dossier?",
"title": "Delete {dossierName}",
"title-alt": "Delete selected Dossiers"
"confirmation-text": "Delete {dossiersCount, plural, one{Dossier} other{Dossiers}}",
"deny-text": "Keep {dossiersCount, plural, one{Dossier} other{Dossiers}}",
"question": "Are you sure you want to delete {dossiersCount, plural, one{this dossier} other{these dossiers}}?",
"title": "Delete {dossiersCount, plural, one{{dossierName}} other{Selected Dossiers}}"
},
"delete-file": {
"question": "Do you wish to proceed?",
"title": "Delete Document"
},
"input-label": "To proceed please type below",
"permanently-delete-file": {
"confirmation-text": "Delete {filesCount, plural, one{Document} other{Documents}}",
"deny-text": "Keep {filesCount, plural, one{Document} other{Documents}}",
"question": "Are you sure you want to delete {filesCount, plural, one{this document} other{these documents}}?",
"title": "Delete {filesCount, plural, one{{fileName}} other{Selected Documents}}"
}
},
"content": "Reason",
@ -772,6 +777,29 @@
},
"change-successful": "Dossier was updated.",
"delete-successful": "Dossier was deleted.",
"deleted-documents": {
"action": {
"delete": "Delete Forever",
"restore": "Restore"
},
"bulk": {
"delete": "Forever Delete Selected Documents",
"restore": "Restore Selected Documents"
},
"instructions": "Deleted items can be restored up to {hours} hours from their deletion",
"no-data": {
"title": "There are no deleted documents."
},
"table-col-names": {
"deleted-on": "Deleted On",
"name": "Name",
"pages": "Pages",
"time-to-restore": "Time To Restore"
},
"table-header": {
"label": "{length} deleted {length, plural, one{document} other{documents}}"
}
},
"dictionary": {
"entries": "{length} {length, plural, one{entry} other{entries}}"
},
@ -793,6 +821,7 @@
"header": "Edit {dossierName}",
"nav-items": {
"choose-download": "Choose what is included at download:",
"deleted-documents": "Deleted Documents",
"dictionary": "Dictionary",
"dossier-attributes": "Dossier Attributes",
"dossier-dictionary": "Dossier Dictionary",
@ -805,7 +834,7 @@
"side-nav-title": "Configurations",
"unsaved-changes": "You have unsaved changes. Save or revert before changing the tab."
},
"exact-comment-date": "{day} {month} {year} at {hour}:{minute}",
"exact-date": "{day} {month} {year} at {hour}:{minute}",
"file-attribute-types": {
"date": "Date",
"number": "Number",
@ -963,6 +992,7 @@
},
"file-status": {
"approved": "Approved",
"deleted": "Deleted",
"error": "Re-processing required",
"excluded": "Excluded",
"full-reprocess": "Processing",
@ -984,13 +1014,13 @@
},
"filter": {
"analysis": "Analysis required",
"comment": "Comments",
"hint": "Hints only",
"image": "Images",
"none": "No Annotations",
"redaction": "Redacted",
"suggestion": "Suggested Redaction",
"updated": "Updated",
"comment": "Comments"
"updated": "Updated"
},
"filters": {
"assigned-people": "Assignee(s)",
@ -1200,7 +1230,6 @@
},
"reports": "Reports",
"reports-screen": {
"invalid-upload": "Invalid format selected for Upload! Supported formats are XLSX and DOCX",
"description": "A short text explaining how to create report documents. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.",
"descriptions": {
"dossier-attributes": "This placeholder gets replaced with the value of the dossier attribute <code>{attribute}</code>.",
@ -1229,6 +1258,7 @@
},
"document-setup-description": "A short text explaining what placeholders are and how to use them in your report template. It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.",
"document-setup-heading": "Document Setup",
"invalid-upload": "Invalid format selected for Upload! Supported formats are XLSX and DOCX",
"report-documents": "Report Documents",
"table-header": {
"description": "Description",
@ -1330,7 +1360,7 @@
},
"trash": {
"action": {
"delete": "Delete forever",
"delete": "Delete Forever",
"restore": "Restore"
},
"bulk": {

View File

@ -325,31 +325,45 @@ export class FileManagementControllerService {
/**
* Hard deletes an uploaded file.
* None
* @param body fileId
* @param dossierId dossierId
* @param fileIds fileIds
* @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 hardDeleteFile(body: Array<string>, dossierId: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
public hardDeleteFile(dossierId: string, fileIds: Array<string>, observe?: 'body', reportProgress?: boolean): Observable<any>;
public hardDeleteFile(
body: Array<string>,
dossierId: string,
fileIds: Array<string>,
observe?: 'response',
reportProgress?: boolean
): Observable<HttpResponse<any>>;
public hardDeleteFile(body: Array<string>, dossierId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public hardDeleteFile(body: Array<string>, dossierId: string, 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 hardDeleteFile.');
}
public hardDeleteFile(
dossierId: string,
fileIds: Array<string>,
observe?: 'events',
reportProgress?: boolean
): Observable<HttpEvent<any>>;
public hardDeleteFile(
dossierId: string,
fileIds: Array<string>,
observe: any = 'body',
reportProgress: boolean = false
): Observable<any> {
if (dossierId === null || dossierId === undefined) {
throw new Error('Required parameter dossierId was null or undefined when calling hardDeleteFile.');
}
if (fileIds === null || fileIds === undefined) {
throw new Error('Required parameter fileIds was null or undefined when calling hardDeleteFile.');
}
let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() });
if (fileIds) {
fileIds.forEach(element => {
queryParameters = queryParameters.append('fileIds', <any>element);
});
}
let headers = this.defaultHeaders;
// authentication (RED-OAUTH) required
@ -366,15 +380,8 @@ export class FileManagementControllerService {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = ['*/*'];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
headers = headers.set('Content-Type', httpContentTypeSelected);
}
return this.httpClient.request<any>('delete', `${this.basePath}/delete/hard-delete/${encodeURIComponent(String(dossierId))}`, {
body: body,
params: queryParameters,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,

View File

@ -41,6 +41,53 @@ export class StatusControllerService {
}
}
/**
* Gets the deleted status for a file.
* None
* @param dossierId dossierId
* @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 getDeletedFileStatus(dossierId: string, observe?: 'body', reportProgress?: boolean): Observable<Array<FileStatus>>;
public getDeletedFileStatus(
dossierId: string,
observe?: 'response',
reportProgress?: boolean
): Observable<HttpResponse<Array<FileStatus>>>;
public getDeletedFileStatus(dossierId: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Array<FileStatus>>>;
public getDeletedFileStatus(dossierId: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (dossierId === null || dossierId === undefined) {
throw new Error('Required parameter dossierId was null or undefined when calling getDeletedFileStatus.');
}
let headers = this.defaultHeaders;
// authentication (RED-OAUTH) required
if (this.configuration.accessToken) {
const accessToken =
typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken;
headers = headers.set('Authorization', 'Bearer ' + accessToken);
}
// to determine the Accept header
const httpHeaderAccepts: string[] = ['application/json'];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
return this.httpClient.request<Array<FileStatus>>(
'get',
`${this.basePath}/status/softdeleted/${encodeURIComponent(String(dossierId))}`,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
* Gets the status for all files in a dossier.
* None

View File

@ -59,6 +59,10 @@ export interface FileStatus {
* Shows if the file was excluded from analysis.
*/
excluded?: boolean;
/**
* Set of excluded pages for this file.
*/
excludedPages?: Array<number>;
fileAttributes?: FileAttributes;
/**
* The ID of the file.
@ -84,10 +88,22 @@ export interface FileStatus {
* Shows if any redactions were found during the analysis.
*/
hasRedactions?: boolean;
/**
* Shows if any requests were found during the analysis.
*/
hasRequests?: boolean;
/**
* Shows if there are any Suggestions in this file.
*/
hasSuggestions?: boolean;
/**
* Shows if there is any change between the previous and current analysis.
*/
hasUpdates?: boolean;
/**
* Date and time when the files attributes was last updated.
*/
lastFileAttributeChange?: string;
/**
* Shows if this file has been OCRed by us. Last Time of OCR.
*/
@ -124,6 +140,10 @@ export interface FileStatus {
* Shows which rules versions was used during the analysis.
*/
rulesVersion?: number;
/**
* Shows if the file is soft deleted.
*/
softDeleted?: string;
/**
* The status of the file with regard to its analysis an review processes.
*/
@ -132,40 +152,36 @@ export interface FileStatus {
* The ID of the user who uploaded the file.
*/
uploader?: string;
/**
* The list of excluded pages.
*/
excludedPages?: number[];
hasSuggestions?: boolean;
}
export namespace FileStatus {
export type StatusEnum =
| 'APPROVED'
| 'DELETED'
| 'ERROR'
| 'EXCLUDED'
| 'FULLREPROCESS'
| 'INDEXING'
| 'OCR_PROCESSING'
| 'PROCESSING'
| 'REPROCESS'
| 'UNASSIGNED'
| 'UNDER_APPROVAL'
| 'UNDER_REVIEW'
| 'UNPROCESSED'
| 'INDEXING';
| 'UNPROCESSED';
export const StatusEnum = {
APPROVED: 'APPROVED' as StatusEnum,
DELETED: 'DELETED' as StatusEnum,
ERROR: 'ERROR' as StatusEnum,
EXCLUDED: 'EXCLUDED' as StatusEnum,
FULLREPROCESS: 'FULLREPROCESS' as StatusEnum,
INDEXING: 'INDEXING' as StatusEnum,
OCRPROCESSING: 'OCR_PROCESSING' as StatusEnum,
PROCESSING: 'PROCESSING' as StatusEnum,
REPROCESS: 'REPROCESS' as StatusEnum,
UNASSIGNED: 'UNASSIGNED' as StatusEnum,
UNDERAPPROVAL: 'UNDER_APPROVAL' as StatusEnum,
UNDERREVIEW: 'UNDER_REVIEW' as StatusEnum,
UNPROCESSED: 'UNPROCESSED' as StatusEnum,
INDEXING: 'INDEXING' as StatusEnum
UNPROCESSED: 'UNPROCESSED' as StatusEnum
} as const;
}

View File

@ -1,6 +1,6 @@
{
"name": "redaction",
"version": "2.175.0",
"version": "2.181.0",
"private": true,
"license": "MIT",
"scripts": {

Binary file not shown.