refactor file status

This commit is contained in:
Dan Percic 2021-08-11 19:54:16 +03:00
parent 86a84393b5
commit d8e758ff14
20 changed files with 142 additions and 297 deletions

View File

@ -1,23 +1,55 @@
import { FileAttributesConfig, FileStatus } from '@redaction/red-ui-http';
import { StatusSorter } from '@utils/sorters/status-sorter';
export class FileStatusWrapper {
const processingStatuses = [
FileStatus.StatusEnum.REPROCESS,
FileStatus.StatusEnum.FULLREPROCESS,
FileStatus.StatusEnum.OCRPROCESSING,
FileStatus.StatusEnum.INDEXING,
FileStatus.StatusEnum.PROCESSING
] as const;
export class FileStatusWrapper implements FileStatus {
readonly added = this.fileStatus.added;
readonly allManualRedactionsApplied = this.fileStatus.allManualRedactionsApplied;
readonly analysisDuration = this.fileStatus.analysisDuration;
readonly analysisRequired = this.fileStatus.analysisRequired && !this.fileStatus.excluded;
readonly approvalDate = this.fileStatus.approvalDate;
currentReviewer = this.fileStatus.currentReviewer;
readonly dictionaryVersion = this.fileStatus.dictionaryVersion;
readonly dossierDictionaryVersion = this.fileStatus.dossierDictionaryVersion;
readonly dossierId = this.fileStatus.dossierId;
readonly excluded = this.fileStatus.excluded;
readonly fileAttributes = this.fileStatus.fileAttributes;
readonly fileId = this.fileStatus.fileId;
readonly filename = this.fileStatus.filename;
readonly hasAnnotationComments = this.fileStatus.hasAnnotationComments;
readonly hasHints = this.fileStatus.hasHints;
readonly hasImages = this.fileStatus.hasImages;
readonly hasRedactions = this.fileStatus.hasRedactions;
readonly hasRequests = this.fileStatus.hasRequests;
readonly hasUpdates = this.fileStatus.hasUpdates;
readonly lastOCRTime = this.fileStatus.lastOCRTime;
readonly lastProcessed = this.fileStatus.lastProcessed;
readonly lastReviewer = this.fileStatus.lastReviewer;
readonly lastUpdated = this.fileStatus.lastUpdated;
readonly lastUploaded = this.fileStatus.lastUploaded;
readonly legalBasisVersion = this.fileStatus.legalBasisVersion;
readonly numberOfAnalyses = this.fileStatus.numberOfAnalyses;
readonly numberOfPages = this.fileStatus.numberOfPages;
readonly rulesVersion = this.fileStatus.rulesVersion;
readonly status = this._status;
readonly uploader = this.fileStatus.uploader;
readonly excludedPages = this.fileStatus.excludedPages;
primaryAttribute: string;
searchField: string;
constructor(
public fileStatus: FileStatus,
public reviewerName: string,
public dossierTemplateId: string,
fileAttributesConfig?: FileAttributesConfig
) {
this.searchField = fileStatus.filename;
constructor(readonly fileStatus: FileStatus, public reviewerName: string, fileAttributesConfig?: FileAttributesConfig) {
if (fileAttributesConfig) {
const primary = fileAttributesConfig.fileAttributeConfigs?.find(c => c.primaryAttribute);
if (primary && fileStatus.fileAttributes?.attributeIdToValue) {
this.primaryAttribute = fileStatus.fileAttributes?.attributeIdToValue[primary.id];
this.searchField += ' ' + this.primaryAttribute;
this.filename += ' ' + this.primaryAttribute;
}
if (!this.primaryAttribute) {
@ -27,178 +59,40 @@ export class FileStatusWrapper {
}
}
get analysisDuration() {
return this.fileStatus.analysisDuration;
readonly excludedPagesCount = this.excludedPages?.length ?? 0;
readonly statusSort = StatusSorter[this.status];
readonly pages = this._pages;
readonly cacheIdentifier = btoa(this.lastUploaded + this.lastOCRTime);
readonly hasUnappliedSuggestions = !this.allManualRedactionsApplied;
readonly hintsOnly = this.hasHints && !this.hasRedactions;
readonly hasNone = !this.hasRedactions && !this.hasHints && !this.hasRequests;
readonly isError = this.status === FileStatus.StatusEnum.ERROR;
readonly isProcessing = processingStatuses.includes(this.status);
readonly isApproved = this.status === FileStatus.StatusEnum.APPROVED;
readonly isPending = this.status === FileStatus.StatusEnum.UNPROCESSED;
readonly isUnderReview = this.status === FileStatus.StatusEnum.UNDERREVIEW;
readonly isUnderApproval = this.status === FileStatus.StatusEnum.UNDERAPPROVAL;
readonly canBeApproved = !this.analysisRequired && !this.hasRequests;
readonly canBeOpened = !this.isError && !this.isPending;
readonly isWorkable = !this.isProcessing && this.canBeOpened;
readonly canBeOCRed = !this.excluded && !this.lastOCRTime && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(this.status);
get isUnassigned() {
return !this.currentReviewer;
}
get lastProcessed() {
return this.fileStatus.lastProcessed;
}
get added() {
return this.fileStatus.added;
}
get lastUploaded() {
return this.fileStatus.lastUploaded;
}
get hasImages() {
return this.fileStatus.hasImages;
}
get hasUpdates() {
return this.fileStatus.hasUpdates && !this.hasRequests;
}
get hasUnappliedSuggestions() {
return !this.fileStatus.allManualRedactionsApplied;
}
get currentReviewer() {
return this.fileStatus.currentReviewer;
}
set currentReviewer(value: string) {
this.fileStatus.currentReviewer = value;
}
get fileId() {
return this.fileStatus.fileId;
}
get filename() {
return this.fileStatus.filename;
}
get hasAnnotationComments() {
// return this.fileStatus.hasAnnotationComments;
// TODO remove this once backend works properly
return false;
}
get ocrTime() {
return this.fileStatus.lastOCRTime;
}
get hasHints() {
return this.fileStatus.hasHints;
}
get hintsOnly() {
return this.fileStatus.hasHints && !this.fileStatus.hasRedactions;
}
get hasRedactions() {
return this.fileStatus.hasRedactions;
}
get hasRequests() {
return this.fileStatus.hasRequests || this.hasUnappliedSuggestions;
}
get hasNone() {
return !this.hasRedactions && !this.hasHints && !this.hasRequests;
}
get lastUpdated() {
return this.fileStatus.lastUpdated;
}
get numberOfAnalyses() {
return this.fileStatus.numberOfAnalyses;
}
get dossierId() {
return this.fileStatus.dossierId;
}
get isExcluded() {
return this.fileStatus.excluded;
}
get status() {
return this.fileStatus.status === 'REPROCESS' || this.fileStatus.status === 'FULLREPROCESS' ? 'PROCESSING' : this.fileStatus.status;
}
get numberOfPages() {
return this.fileStatus.numberOfPages;
}
get numberOfExcludedPages() {
return this.fileStatus.excludedPages?.length || 0;
}
get uploader() {
return this.fileStatus.uploader;
}
get isPending() {
return this.status === FileStatus.StatusEnum.UNPROCESSED;
}
get isProcessing() {
return [
FileStatus.StatusEnum.REPROCESS,
FileStatus.StatusEnum.FULLREPROCESS,
FileStatus.StatusEnum.OCRPROCESSING,
FileStatus.StatusEnum.INDEXING,
FileStatus.StatusEnum.PROCESSING
].includes(this.status);
}
get analysisRequired() {
return this.fileStatus.analysisRequired && !this.fileStatus.excluded;
}
get statusSort() {
return StatusSorter[this.status];
}
get isWorkable() {
return !this.isProcessing && !this.isPending && !this.isError;
}
get isApproved() {
return this.fileStatus.status === 'APPROVED';
}
get isError() {
return this.fileStatus.status === 'ERROR';
}
get pages() {
private get _pages() {
if (this.fileStatus.status === 'ERROR') {
return -1;
}
return this.fileStatus.numberOfPages ? this.fileStatus.numberOfPages : 0;
}
get isApprovedOrUnderApproval() {
return this.status === 'APPROVED' || this.status === 'UNDER_APPROVAL';
}
get isUnassigned() {
return !this.currentReviewer;
}
get isUnderReview() {
return this.fileStatus.status === 'UNDER_REVIEW';
}
get isUnderApproval() {
return this.fileStatus.status === 'UNDER_APPROVAL';
}
get canApprove() {
return this.status === 'UNDER_REVIEW' || this.status === 'UNDER_APPROVAL';
}
get cacheIdentifier() {
return btoa(this.fileStatus.lastUploaded + this.fileStatus.lastOCRTime);
}
get excludedPages(): number[] {
return this.fileStatus.excludedPages;
private get _status(): FileStatus.StatusEnum {
return this.fileStatus.status === FileStatus.StatusEnum.REPROCESS || this.fileStatus.status === FileStatus.StatusEnum.FULLREPROCESS
? FileStatus.StatusEnum.PROCESSING
: this.fileStatus.status;
}
}

View File

@ -1,7 +1,7 @@
<div class="action-buttons">
<iqser-circle-button
(action)="openDeleteDossierTemplateDialog($event)"
*ngIf="permissionsService.isAdmin()"
*ngIf="currentUser.isAdmin"
[tooltip]="'dossier-templates-listing.action.delete' | translate"
icon="red:trash"
[type]="circleButtonTypes.dark"
@ -9,7 +9,7 @@
<iqser-circle-button
(action)="openEditDossierTemplateDialog($event)"
*ngIf="permissionsService.isAdmin()"
*ngIf="currentUser.isAdmin"
[tooltip]="'dossier-templates-listing.action.edit' | translate"
icon="red:edit"
[type]="circleButtonTypes.dark"

View File

@ -1,34 +1,35 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { PermissionsService } from '@services/permissions.service';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { Router } from '@angular/router';
import { AdminDialogService } from '../../services/admin-dialog.service';
import { DossierTemplateControllerService } from '@redaction/red-ui-http';
import { LoadingService } from '@services/loading.service';
import { CircleButtonTypes } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
@Component({
selector: 'redaction-dossier-template-actions',
templateUrl: './dossier-template-actions.component.html',
styleUrls: ['./dossier-template-actions.component.scss']
})
export class DossierTemplateActionsComponent {
export class DossierTemplateActionsComponent implements OnInit {
readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser = this._userService.currentUser;
@Input() dossierTemplateId: string;
@Output() loadDossierTemplatesData = new EventEmitter<any>();
constructor(
private readonly _dialogService: AdminDialogService,
private readonly _appStateService: AppStateService,
private readonly _dossierTemplateControllerService: DossierTemplateControllerService,
private readonly _loadingService: LoadingService,
private readonly _router: Router,
readonly permissionsService: PermissionsService
) {
if (!this.dossierTemplateId) {
this.dossierTemplateId = this._appStateService.activeDossierTemplateId;
}
private readonly _userService: UserService,
private readonly _loadingService: LoadingService,
private readonly _appStateService: AppStateService,
private readonly _dialogService: AdminDialogService,
private readonly _dossierTemplateControllerService: DossierTemplateControllerService
) {}
ngOnInit() {
this.dossierTemplateId ??= this._appStateService.activeDossierTemplateId;
}
get dossierTemplate() {
@ -48,9 +49,7 @@ export class DossierTemplateActionsComponent {
await this._appStateService.loadAllDossierTemplates();
await this._appStateService.loadDictionaryData();
await this._router.navigate(['main', 'admin']);
if (this.loadDossierTemplatesData) {
this.loadDossierTemplatesData.emit();
}
this.loadDossierTemplatesData?.emit();
});
}
}

View File

@ -5,7 +5,7 @@
<div class="actions">
<iqser-circle-button
(action)="openDeleteDictionaryDialog($event)"
*ngIf="permissionsService.isAdmin()"
*ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.delete' | translate"
icon="red:trash"
tooltipPosition="below"
@ -14,7 +14,7 @@
<iqser-circle-button
(action)="openEditDictionaryDialog($event)"
*ngIf="permissionsService.isAdmin()"
*ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.edit' | translate"
icon="red:edit"
tooltipPosition="below"
@ -30,7 +30,7 @@
<iqser-circle-button
(action)="fileInput.click()"
*ngIf="permissionsService.isAdmin()"
*ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.upload' | translate"
icon="red:upload"
tooltipPosition="below"
@ -56,7 +56,7 @@
<redaction-dictionary-manager
#dictionaryManager
(saveDictionary)="saveEntries($event)"
[canEdit]="permissionsService.isAdmin()"
[canEdit]="currentUser.isAdmin"
[initialEntries]="entries"
></redaction-dictionary-manager>

View File

@ -1,7 +1,6 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { DictionaryControllerService } from '@redaction/red-ui-http';
import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { saveAs } from 'file-saver';
@ -12,6 +11,7 @@ import { DictionarySaveService } from '@shared/services/dictionary-save.service'
import { TypeValueWrapper } from '@models/file/type-value.wrapper';
import { LoadingService } from '@services/loading.service';
import { CircleButtonTypes } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
@Component({
templateUrl: './dictionary-overview-screen.component.html',
@ -19,33 +19,32 @@ import { CircleButtonTypes } from '@iqser/common-ui';
})
export class DictionaryOverviewScreenComponent extends ComponentHasChanges implements OnInit {
readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser = this._userService.currentUser;
entries: string[] = [];
dictionary: TypeValueWrapper;
@ViewChild('dictionaryManager', { static: false })
private readonly _dictionaryManager: DictionaryManagerComponent;
@ViewChild('fileInput') private readonly _fileInput: ElementRef;
constructor(
readonly permissionsService: PermissionsService,
private readonly _router: Router,
private readonly _userService: UserService,
private readonly _activatedRoute: ActivatedRoute,
private readonly _loadingService: LoadingService,
private readonly _appStateService: AppStateService,
private readonly _dialogService: AdminDialogService,
protected readonly _translateService: TranslateService,
private readonly _dictionarySaveService: DictionarySaveService,
private readonly _dictionaryControllerService: DictionaryControllerService,
private readonly _dialogService: AdminDialogService,
private readonly _router: Router,
private readonly _activatedRoute: ActivatedRoute,
private readonly _appStateService: AppStateService,
private readonly _loadingService: LoadingService
private readonly _dictionaryControllerService: DictionaryControllerService
) {
super(_translateService);
this._appStateService.activateDictionary(
this._activatedRoute.snapshot.params.type,
this._activatedRoute.snapshot.params.dossierTemplateId
);
}
get dictionary(): TypeValueWrapper {
return this._appStateService.activeDictionary;
this.dictionary = this._appStateService.activeDictionary;
}
get hasChanges() {
@ -67,6 +66,7 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple
async () => {
this._loadingService.start();
await this._appStateService.loadDictionaryData();
this.dictionary = this._appStateService.activeDictionary;
this._loadingService.stop();
}
);

View File

@ -89,7 +89,7 @@ export class DossierOverviewBulkActionsComponent {
}
get canOcr() {
return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canOcrFile(file), true);
return this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true);
}
get fileStatuses() {
@ -112,7 +112,7 @@ export class DossierOverviewBulkActionsComponent {
}
get canApprove() {
return this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canApprove(file), true);
return this.selectedFiles.reduce((acc, file) => acc && file.canBeApproved, true);
}
// Undo approval
@ -163,7 +163,7 @@ export class DossierOverviewBulkActionsComponent {
}
async reanalyse() {
const fileIds = this.selectedFiles.filter(file => this._permissionsService.fileRequiresReanalysis(file)).map(file => file.fileId);
const fileIds = this.selectedFiles.filter(file => file.analysisRequired).map(file => file.fileId);
this._performBulkAction(
this._reanalysisControllerService.reanalyzeFilesForDossier(fileIds, this._appStateService.activeDossier.dossierId)
);

View File

@ -88,9 +88,11 @@
<iqser-circle-button
(action)="setFileApproved($event)"
*ngIf="readyForApproval"
[disabled]="!canApprove"
[disabled]="!fileStatus.canBeApproved"
[tooltipPosition]="tooltipPosition"
[tooltip]="canApprove ? ('dossier-overview.approve' | translate) : ('dossier-overview.approve-disabled' | translate)"
[tooltip]="
fileStatus.canBeApproved ? ('dossier-overview.approve' | translate) : ('dossier-overview.approve-disabled' | translate)
"
[type]="buttonType"
icon="red:approved"
></iqser-circle-button>
@ -107,7 +109,7 @@
<iqser-circle-button
(action)="ocrFile($event)"
*ngIf="canOcr"
*ngIf="fileStatus.canBeOCRed"
[tooltipPosition]="tooltipPosition"
[tooltip]="'dossier-overview.ocr-file' | translate"
[type]="buttonType"
@ -140,7 +142,7 @@
<mat-slide-toggle
(change)="toggleAnalysis()"
(click)="$event.stopPropagation()"
[checked]="!fileStatus?.isExcluded"
[checked]="!fileStatus?.excluded"
[class.mr-24]="screen === 'dossier-overview'"
[disabled]="!canToggleAnalysis"
[matTooltipPosition]="tooltipPosition"

View File

@ -39,10 +39,8 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
canAssign: boolean;
canDelete: boolean;
canReanalyse: boolean;
canOcr: boolean;
canSetToUnderReview: boolean;
canSetToUnderApproval: boolean;
canApprove: boolean;
readyForApproval: boolean;
canToggleAnalysis: boolean;
@ -63,7 +61,7 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
return _('file-preview.toggle-analysis.only-managers');
}
return this.fileStatus?.isExcluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable');
return this.fileStatus?.excluded ? _('file-preview.toggle-analysis.enable') : _('file-preview.toggle-analysis.disable');
}
private _setup() {
@ -81,10 +79,8 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
this.canAssign = this.permissionsService.canAssignUser(this.fileStatus);
this.canDelete = this.permissionsService.canDeleteFile(this.fileStatus);
this.canReanalyse = this.permissionsService.canReanalyseFile(this.fileStatus);
this.canOcr = this.permissionsService.canOcrFile(this.fileStatus);
this.canSetToUnderReview = this.permissionsService.canSetUnderReview(this.fileStatus);
this.canSetToUnderApproval = this.permissionsService.canSetUnderApproval(this.fileStatus);
this.canApprove = this.permissionsService.canApprove(this.fileStatus);
this.readyForApproval = this.permissionsService.isReadyForApproval(this.fileStatus);
this.canToggleAnalysis = this.permissionsService.canToggleAnalysis(this.fileStatus);
}
@ -206,6 +202,6 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
async toggleAnalysis() {
await this._fileActionService.toggleAnalysis(this.fileStatus).toPromise();
await this.appStateService.getFiles();
this.actionPerformed.emit(this.fileStatus?.isExcluded ? 'enable-analysis' : 'disable-analysis');
this.actionPerformed.emit(this.fileStatus?.excluded ? 'enable-analysis' : 'disable-analysis');
}
}

View File

@ -1,6 +1,5 @@
import { Component, Input } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
import { DossierWrapper } from '@state/model/dossier.wrapper';
@ -12,7 +11,7 @@ import { DossierWrapper } from '@state/model/dossier.wrapper';
export class NeedsWorkBadgeComponent {
@Input() needsWorkInput: FileStatusWrapper | DossierWrapper;
constructor(private readonly _appStateService: AppStateService, private readonly _permissionsService: PermissionsService) {}
constructor(private readonly _appStateService: AppStateService) {}
get suggestionColor() {
return this._getDictionaryColor('suggestion');
@ -52,9 +51,9 @@ export class NeedsWorkBadgeComponent {
reanalysisRequired() {
if (this.needsWorkInput instanceof DossierWrapper) {
return this._permissionsService.dossierReanalysisRequired(this.needsWorkInput);
return this.needsWorkInput.reanalysisRequired;
} else {
return this._permissionsService.fileRequiresReanalysis(this.needsWorkInput);
return this.needsWorkInput.analysisRequired;
}
}

View File

@ -251,8 +251,7 @@ export class DossierListingScreenComponent
filterTemplate: this._needsWorkTemplate,
filters: needsWorkFilters.sort(RedactionFilterSorter.byKey),
checker: annotationFilterChecker,
matchAll: true,
checkerArgs: [this.permissionsService]
matchAll: true
});
const dossierTemplateFilters = [...allDistinctDossierTemplates].map<NestedFilter>(id => ({

View File

@ -57,9 +57,9 @@
<cdk-virtual-scroll-viewport #scrollViewport [itemSize]="itemSize" redactionHasScrollbar>
<div
*cdkVirtualFor="let fileStatus of sortedDisplayedEntities$ | async; trackBy: trackByPrimaryKey"
[class.disabled]="fileStatus.isExcluded"
[class.disabled]="fileStatus.excluded"
[class.last-opened]="isLastOpenedFile(fileStatus.fileId)"
[class.pointer]="permissionsService.canOpenFile(fileStatus)"
[class.pointer]="fileStatus.canBeOpened"
[routerLink]="fileLink(fileStatus)"
class="table-item"
>
@ -93,15 +93,15 @@
</div>
<div>
<mat-icon svgIcon="red:exclude-pages"></mat-icon>
{{ fileStatus.numberOfExcludedPages }}
{{ fileStatus.excludedPagesCount }}
</div>
<div
*ngIf="fileStatus.ocrTime"
*ngIf="fileStatus.lastOCRTime"
[matTooltipPosition]="'above'"
[matTooltip]="'dossier-overview.ocr-performed' | translate"
>
<mat-icon svgIcon="red:ocr"></mat-icon>
{{ fileStatus.ocrTime | date: 'mediumDate' }}
{{ fileStatus.lastOCRTime | date: 'mediumDate' }}
</div>
</div>
</div>

View File

@ -144,7 +144,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
.subscribe();
this.dossierAttributes = await this._dossierAttributesService.getValues(this.currentDossier);
this.searchService.setSearchKey('searchField');
this.searchService.setSearchKey('filename');
} catch (e) {
} finally {
this._loadingService.stop();
@ -210,9 +210,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
}
fileLink(fileStatus: FileStatusWrapper) {
return this.permissionsService.canOpenFile(fileStatus)
? [`/main/dossiers/${this.currentDossier.dossierId}/file/${fileStatus.fileId}`]
: [];
return fileStatus.canBeOpened ? [`/main/dossiers/${this.currentDossier.dossierId}/file/${fileStatus.fileId}`] : [];
}
bulkActionPerformed() {
@ -274,7 +272,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
allDistinctFileStatusWrapper.add(file.status);
allDistinctAddedDates.add(moment(file.added).format('DD/MM/YYYY'));
if (this.permissionsService.fileRequiresReanalysis(file)) allDistinctNeedsWork.add('analysis');
if (file.analysisRequired) allDistinctNeedsWork.add('analysis');
if (file.hintsOnly) allDistinctNeedsWork.add('hint');
if (file.hasRedactions) allDistinctNeedsWork.add('redaction');
if (file.hasRequests) allDistinctNeedsWork.add('suggestion');
@ -331,8 +329,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
filterTemplate: this._needsWorkTemplate,
filters: needsWorkFilters.sort(RedactionFilterSorter.byKey),
checker: annotationFilterChecker,
matchAll: true,
checkerArgs: [this.permissionsService]
matchAll: true
});
this.filterService.addFilterGroup({

View File

@ -30,7 +30,7 @@
</div>
<div class="flex-1 actions-container">
<ng-container *ngIf="!appStateService.activeFile.isExcluded">
<ng-container *ngIf="!appStateService.activeFile.excluded">
<ng-container *ngIf="!appStateService.activeFile.isProcessing">
<iqser-status-bar [configs]="statusBarConfig" [small]="true"></iqser-status-bar>
@ -148,7 +148,7 @@
<div class="right-container">
<redaction-empty-state
*ngIf="appStateService.activeFile.isExcluded && !viewDocumentInfo && !excludePages"
*ngIf="appStateService.activeFile.excluded && !viewDocumentInfo && !excludePages"
[horizontalPadding]="40"
[text]="'file-preview.tabs.is-excluded' | translate"
icon="red:needs-work"
@ -168,7 +168,7 @@
(selectAnnotations)="selectAnnotations($event)"
(selectPage)="selectPage($event)"
(toggleSkipped)="toggleSkipped($event)"
*ngIf="!appStateService.activeFile.isExcluded"
*ngIf="!appStateService.activeFile.excluded"
[(shouldDeselectAnnotationsOnPageChange)]="shouldDeselectAnnotationsOnPageChange"
[activeViewerPage]="activeViewerPage"
[annotationActionsTemplate]="annotationActionsTemplate"

View File

@ -131,11 +131,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
get canSwitchToRedactedView() {
return this.fileData && !this.permissionsService.fileRequiresReanalysis() && !this.fileData.fileStatus.isExcluded;
return this.fileData && !this.fileData.fileStatus.analysisRequired && !this.fileData.fileStatus.excluded;
}
get canSwitchToDeltaView() {
return this.fileData?.redactionChangeLog?.redactionLogEntry?.length > 0 && !this.fileData.fileStatus.isExcluded;
return this.fileData?.redactionChangeLog?.redactionLogEntry?.length > 0 && !this.fileData.fileStatus.excluded;
}
get canAssign(): boolean {
@ -231,7 +231,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
async ngOnAttach(previousRoute: ActivatedRouteSnapshot) {
if (!this.permissionsService.canOpenFile(this.appStateService.activeFile)) {
if (!this.appStateService.activeFile.canBeOpened) {
await this._router.navigate(['/main/dossiers/' + this.dossierId]);
return;
}

View File

@ -38,7 +38,7 @@ export class FileActionService {
return this._reanalysisControllerService.toggleAnalysis(
fileStatusWrapper.dossierId,
fileStatusWrapper.fileId,
!fileStatusWrapper.isExcluded
!fileStatusWrapper.excluded
);
}

View File

@ -1,6 +1,5 @@
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
import { DossierWrapper } from '@state/model/dossier.wrapper';
import { PermissionsService } from '@services/permissions.service';
import { handleCheckedValue, NestedFilter } from '@iqser/common-ui';
export function handleFilterDelta(oldFilters: NestedFilter[], newFilters: NestedFilter[], allFilters: NestedFilter[]) {
@ -46,17 +45,13 @@ export function handleFilterDelta(oldFilters: NestedFilter[], newFilters: Nested
});
}
export const annotationFilterChecker = (
input: FileStatusWrapper | DossierWrapper,
filter: NestedFilter,
permissionsService: PermissionsService
) => {
export const annotationFilterChecker = (input: FileStatusWrapper | DossierWrapper, filter: NestedFilter) => {
switch (filter.key) {
case 'analysis': {
if (input instanceof DossierWrapper) {
return permissionsService.dossierReanalysisRequired(input);
return input.reanalysisRequired;
} else {
return permissionsService.fileRequiresReanalysis(input);
return input.analysisRequired;
}
}
case 'suggestion': {

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { UserService, UserWrapper } from './user.service';
import { UserService } from './user.service';
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
import { Comment } from '@redaction/red-ui-http';
import { DossierWrapper } from '@state/model/dossier.wrapper';
@ -23,16 +23,8 @@ export class PermissionsService {
return this.isFileReviewer(fileStatus) || this.isApprover();
}
dossierReanalysisRequired(dossier: DossierWrapper): boolean {
for (const file of dossier.files) if (this.fileRequiresReanalysis(file)) return true;
}
fileRequiresReanalysis(fileStatus = this._activeFile): boolean {
return fileStatus.analysisRequired;
}
displayReanalyseBtn(dossier = this._activeDossier): boolean {
return this.isApprover(dossier) && dossier.files.filter(file => this.fileRequiresReanalysis(file)).length > 0;
return this.isApprover(dossier) && dossier.files.filter(file => file.analysisRequired).length > 0;
}
canToggleAnalysis(fileStatus: FileStatusWrapper): boolean {
@ -41,7 +33,7 @@ export class PermissionsService {
canReanalyseFile(fileStatus = this._activeFile): boolean {
return (
(this.fileRequiresReanalysis(fileStatus) && (this.isReviewerOrApprover(fileStatus) || fileStatus.isUnassigned)) ||
(fileStatus.analysisRequired && (this.isReviewerOrApprover(fileStatus) || fileStatus.isUnassigned)) ||
(fileStatus.isError && fileStatus.isUnassigned)
);
}
@ -54,10 +46,6 @@ export class PermissionsService {
return this.isOwner(dossier) || fileStatus.isUnassigned;
}
isApprovedOrUnderApproval(fileStatus = this._activeFile): boolean {
return fileStatus.isApprovedOrUnderApproval;
}
canAssignToSelf(fileStatus = this._activeFile): boolean {
const precondition = this.isDossierMember() && !fileStatus.isProcessing && !fileStatus.isError && !fileStatus.isApproved;
@ -96,10 +84,6 @@ export class PermissionsService {
return this.canSetUnderReview(fileStatus);
}
canApprove(fileStatus = this._activeFile): boolean {
return !fileStatus?.analysisRequired && !fileStatus.hasRequests;
}
canSetUnderApproval(fileStatus = this._activeFile): boolean {
return fileStatus?.isUnderReview && this.isReviewerOrApprover(fileStatus);
}
@ -124,18 +108,10 @@ export class PermissionsService {
return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus?.status) && this.isFileReviewer(fileStatus);
}
canOpenFile(fileStatus = this._activeFile): boolean {
return !fileStatus?.isError && !fileStatus?.isPending;
}
canUndoApproval(fileStatus = this._activeFile): boolean {
return fileStatus?.isApproved && this.isApprover();
}
canUndoUnderApproval(fileStatus = this._activeFile): boolean {
return fileStatus?.isUnderApproval && this.isDossierMember();
}
canMarkPagesAsViewed(fileStatus = this._activeFile): boolean {
return ['UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus?.status) && this.isFileReviewer(fileStatus);
}
@ -155,16 +131,6 @@ export class PermissionsService {
return user.isAdmin;
}
canOcrFile(fileStatus = this._activeFile): boolean {
return (
!fileStatus.isExcluded && !fileStatus.ocrTime && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(fileStatus.status)
);
}
canManageUsers(user: UserWrapper = this._userService.currentUser): boolean {
return user.isUserAdmin;
}
canAddComment(fileStatus = this._activeFile): boolean {
return (this.isFileReviewer(fileStatus) || this.isApprover()) && !fileStatus.isApproved;
}

View File

@ -243,7 +243,6 @@ export class AppStateService {
const activeFileWrapper = new FileStatusWrapper(
activeFile,
this._userService.getNameForId(activeFile.currentReviewer),
this.activeDossierTemplateId,
this._appState.fileAttributesConfig[this.activeDossierTemplateId]
);
this.activeDossier.files = this.activeDossier?.files.map(file =>
@ -669,7 +668,6 @@ export class AppStateService {
const fileStatusWrapper = new FileStatusWrapper(
file,
this._userService.getNameForId(file.currentReviewer),
dossier.dossierTemplateId,
this._appState.fileAttributesConfig[dossier.dossierTemplateId]
);
if (JSON.stringify(oldFile) !== JSON.stringify(fileStatusWrapper)) {
@ -687,7 +685,6 @@ export class AppStateService {
const fsw = new FileStatusWrapper(
file,
this._userService.getNameForId(file.currentReviewer),
dossier.dossierTemplateId,
this._appState.fileAttributesConfig[dossier.dossierTemplateId]
);
fileStatusChangedEvent.push(fsw);
@ -699,7 +696,6 @@ export class AppStateService {
new FileStatusWrapper(
f,
this._userService.getNameForId(f.currentReviewer),
dossier.dossierTemplateId,
this._appState.fileAttributesConfig[dossier.dossierTemplateId]
)
);

View File

@ -24,6 +24,7 @@ export class DossierWrapper implements Dossier {
readonly hasMoreThanOneReviewer = this.memberIds.length > 1;
readonly memberCount = this.memberIds.length;
reanalysisRequired = this._files.some(file => file.analysisRequired);
hasFiles = this._files.length > 0;
filesLength = this._files.length;
@ -81,5 +82,6 @@ export class DossierWrapper implements Dossier {
this.hasNone = !this.hasRequests && !this.hasRedactions && !this.hintsOnly;
this.hasFiles = this._files.length > 0;
this.filesLength = this._files.length;
this.reanalysisRequired = this._files.some(file => file.analysisRequired);
}
}

View File

@ -169,5 +169,5 @@ export namespace FileStatus {
UNDERREVIEW: 'UNDER_REVIEW' as StatusEnum,
UNPROCESSED: 'UNPROCESSED' as StatusEnum,
INDEXING: 'INDEXING' as StatusEnum
};
} as const;
}