reworked analysis required
This commit is contained in:
parent
5f16c2988e
commit
1f2acf201e
@ -1,8 +1,10 @@
|
|||||||
import { FilterModel } from '../model/filter.model';
|
import { FilterModel } from '../model/filter.model';
|
||||||
import { FileStatusWrapper } from '../../../screens/file/model/file-status.wrapper';
|
import { FileStatusWrapper } from '../../../screens/file/model/file-status.wrapper';
|
||||||
import { ProjectWrapper } from '../../../state/model/project.wrapper';
|
import { ProjectWrapper } from '../../../state/model/project.wrapper';
|
||||||
|
import { PermissionsService } from '../../service/permissions.service';
|
||||||
|
|
||||||
export const RedactionFilterSorter = {
|
export const RedactionFilterSorter = {
|
||||||
|
analysis: 0,
|
||||||
hint: 1,
|
hint: 1,
|
||||||
redaction: 2,
|
redaction: 2,
|
||||||
suggestion: 3,
|
suggestion: 3,
|
||||||
@ -22,9 +24,16 @@ export function handleCheckedValue(filter: FilterModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkFilter(entity: any, filters: FilterModel[], validate: Function, matchAll: boolean = false) {
|
export function checkFilter(entity: any, filters: FilterModel[], validate: Function, validateArgs: any = [], matchAll: boolean = false) {
|
||||||
const hasChecked = filters.find((f) => f.checked);
|
const hasChecked = filters.find((f) => f.checked);
|
||||||
|
|
||||||
|
if (validateArgs) {
|
||||||
|
if (!Array.isArray(validateArgs)) {
|
||||||
|
validateArgs = [validateArgs];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
validateArgs = [];
|
||||||
|
}
|
||||||
if (!hasChecked) {
|
if (!hasChecked) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -33,9 +42,9 @@ export function checkFilter(entity: any, filters: FilterModel[], validate: Funct
|
|||||||
for (const filter of filters) {
|
for (const filter of filters) {
|
||||||
if (filter.checked) {
|
if (filter.checked) {
|
||||||
if (matchAll) {
|
if (matchAll) {
|
||||||
filterMatched = filterMatched && validate(entity, filter);
|
filterMatched = filterMatched && validate(entity, filter, ...validateArgs);
|
||||||
} else {
|
} else {
|
||||||
filterMatched = filterMatched || validate(entity, filter);
|
filterMatched = filterMatched || validate(entity, filter, ...validateArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,19 +54,26 @@ export function checkFilter(entity: any, filters: FilterModel[], validate: Funct
|
|||||||
|
|
||||||
export const keyChecker = (key: string) => (entity: any, filter: FilterModel) => entity[key] === filter.key;
|
export const keyChecker = (key: string) => (entity: any, filter: FilterModel) => entity[key] === filter.key;
|
||||||
|
|
||||||
export const annotationFilterChecker = (f: FileStatusWrapper, filter: FilterModel) => {
|
export const annotationFilterChecker = (input: FileStatusWrapper | ProjectWrapper, filter: FilterModel, permissionsService: PermissionsService) => {
|
||||||
switch (filter.key) {
|
switch (filter.key) {
|
||||||
|
case 'analysis': {
|
||||||
|
if (input instanceof ProjectWrapper) {
|
||||||
|
return permissionsService.projectReanalysisRequired(input);
|
||||||
|
} else {
|
||||||
|
return permissionsService.fileRequiresReanalysis(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'suggestion': {
|
case 'suggestion': {
|
||||||
return f.hasRequests;
|
return input.hasRequests;
|
||||||
}
|
}
|
||||||
case 'redaction': {
|
case 'redaction': {
|
||||||
return f.hasRedactions;
|
return input.hasRedactions;
|
||||||
}
|
}
|
||||||
case 'hint': {
|
case 'hint': {
|
||||||
return f.hintsOnly;
|
return input.hintsOnly;
|
||||||
}
|
}
|
||||||
case 'none': {
|
case 'none': {
|
||||||
return f.hasNone;
|
return input.hasNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -72,12 +88,12 @@ export const dueDateChecker = (pw: ProjectWrapper, filter: FilterModel) => pw.du
|
|||||||
|
|
||||||
export const addedDateChecker = (pw: ProjectWrapper, filter: FilterModel) => pw.addedDateMatches(filter.key);
|
export const addedDateChecker = (pw: ProjectWrapper, filter: FilterModel) => pw.addedDateMatches(filter.key);
|
||||||
|
|
||||||
export function getFilteredEntities(entities: any[], filters: { values: FilterModel[]; checker: Function; matchAll?: boolean }[]) {
|
export function getFilteredEntities(entities: any[], filters: { values: FilterModel[]; checker: Function; matchAll?: boolean; checkerArgs?: any }[]) {
|
||||||
const filteredEntities = [];
|
const filteredEntities = [];
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
let add = true;
|
let add = true;
|
||||||
for (const filter of filters) {
|
for (const filter of filters) {
|
||||||
add = add && checkFilter(entity, filter.values, filter.checker, filter.matchAll);
|
add = add && checkFilter(entity, filter.values, filter.checker, filter.checkerArgs, filter.matchAll);
|
||||||
}
|
}
|
||||||
if (add) {
|
if (add) {
|
||||||
filteredEntities.push(entity);
|
filteredEntities.push(entity);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { AppStateService } from '../../state/app-state.service';
|
|||||||
import { UserService, UserWrapper } from '../../user/user.service';
|
import { UserService, UserWrapper } from '../../user/user.service';
|
||||||
import { FileStatusWrapper } from '../../screens/file/model/file-status.wrapper';
|
import { FileStatusWrapper } from '../../screens/file/model/file-status.wrapper';
|
||||||
import { Project, User } from '@redaction/red-ui-http';
|
import { Project, User } from '@redaction/red-ui-http';
|
||||||
|
import { ProjectWrapper } from '../../state/model/project.wrapper';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -22,6 +23,15 @@ export class PermissionsService {
|
|||||||
return this.isFileReviewer(fileStatus) || this.isManagerAndOwner();
|
return this.isFileReviewer(fileStatus) || this.isManagerAndOwner();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
projectReanalysisRequired(project?: ProjectWrapper) {
|
||||||
|
for (let file of project.files) {
|
||||||
|
const fileReanalysisRequired = this.fileRequiresReanalysis(file);
|
||||||
|
if (fileReanalysisRequired) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fileRequiresReanalysis(fileStatus?: FileStatusWrapper) {
|
fileRequiresReanalysis(fileStatus?: FileStatusWrapper) {
|
||||||
if (!fileStatus) {
|
if (!fileStatus) {
|
||||||
fileStatus = this._appStateService.activeFile;
|
fileStatus = this._appStateService.activeFile;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<div class="needs-work">
|
<div class="needs-work">
|
||||||
|
<redaction-annotation-icon *ngIf="reanalysisRequired()" [typeValue]="appStateService.getDictionaryTypeValue('analysis')"></redaction-annotation-icon>
|
||||||
<redaction-annotation-icon
|
<redaction-annotation-icon
|
||||||
*ngIf="needsWorkInput.hasRedactions"
|
*ngIf="needsWorkInput.hasRedactions"
|
||||||
[typeValue]="appStateService.getDictionaryTypeValue('redaction')"
|
[typeValue]="appStateService.getDictionaryTypeValue('redaction')"
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { AppStateService } from '../../../state/app-state.service';
|
import { AppStateService } from '../../../state/app-state.service';
|
||||||
|
import { PermissionsService } from '../../../common/service/permissions.service';
|
||||||
export interface NeedsWorkInput {
|
import { FileStatusWrapper } from '../../file/model/file-status.wrapper';
|
||||||
hintsOnly?: boolean;
|
import { ProjectWrapper } from '../../../state/model/project.wrapper';
|
||||||
hasRedactions?: boolean;
|
|
||||||
hasRequests?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-needs-work-badge',
|
selector: 'redaction-needs-work-badge',
|
||||||
@ -13,9 +10,17 @@ export interface NeedsWorkInput {
|
|||||||
styleUrls: ['./needs-work-badge.component.scss']
|
styleUrls: ['./needs-work-badge.component.scss']
|
||||||
})
|
})
|
||||||
export class NeedsWorkBadgeComponent implements OnInit {
|
export class NeedsWorkBadgeComponent implements OnInit {
|
||||||
@Input() needsWorkInput: NeedsWorkInput;
|
@Input() needsWorkInput: FileStatusWrapper | ProjectWrapper;
|
||||||
|
|
||||||
constructor(public appStateService: AppStateService) {}
|
constructor(public appStateService: AppStateService, public permissionsService: PermissionsService) {}
|
||||||
|
|
||||||
ngOnInit(): void {}
|
ngOnInit(): void {}
|
||||||
|
|
||||||
|
reanalysisRequired() {
|
||||||
|
if (this.needsWorkInput instanceof ProjectWrapper) {
|
||||||
|
return this.permissionsService.projectReanalysisRequired(this.needsWorkInput);
|
||||||
|
} else {
|
||||||
|
return this.permissionsService.fileRequiresReanalysis(this.needsWorkInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-1 filename page-title">
|
<div class="flex-1 filename page-title">
|
||||||
<span *ngIf="permissionsService.fileRequiresReanalysis()" class="pill" translate="project-overview.new-rule.label"></span>
|
<!-- <span *ngIf="permissionsService.fileRequiresReanalysis()" class="pill" translate="project-overview.new-rule.label"></span>-->
|
||||||
<span *ngIf="!permissionsService.canPerformAnnotationActions()" class="pill" translate="readonly-pill"></span> <span>{{
|
<span *ngIf="!permissionsService.canPerformAnnotationActions()" class="pill" translate="readonly-pill"></span> <span>{{
|
||||||
appStateService.activeFile.filename
|
appStateService.activeFile.filename
|
||||||
}}</span>
|
}}</span>
|
||||||
|
|||||||
@ -167,10 +167,11 @@ export class ProjectListingScreenComponent implements OnInit {
|
|||||||
|
|
||||||
// Needs work
|
// Needs work
|
||||||
entry.files.forEach((file) => {
|
entry.files.forEach((file) => {
|
||||||
if (file.hintsOnly) allDistinctNeedsWork.add('hint');
|
if (this.permissionsService.fileRequiresReanalysis(file)) allDistinctNeedsWork.add('analysis');
|
||||||
if (file.hasRedactions) allDistinctNeedsWork.add('redaction');
|
if (entry.hintsOnly) allDistinctNeedsWork.add('hint');
|
||||||
if (file.hasRequests) allDistinctNeedsWork.add('suggestion');
|
if (entry.hasRedactions) allDistinctNeedsWork.add('redaction');
|
||||||
if (file.hasNone) allDistinctNeedsWork.add('none');
|
if (entry.hasRequests) allDistinctNeedsWork.add('suggestion');
|
||||||
|
if (entry.hasNone) allDistinctNeedsWork.add('none');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -226,7 +227,7 @@ export class ProjectListingScreenComponent implements OnInit {
|
|||||||
{ values: this.statusFilters, checker: projectStatusChecker },
|
{ values: this.statusFilters, checker: projectStatusChecker },
|
||||||
{ values: this.peopleFilters, checker: projectMemberChecker },
|
{ values: this.peopleFilters, checker: projectMemberChecker },
|
||||||
{ values: this.dueDateFilters, checker: dueDateChecker },
|
{ values: this.dueDateFilters, checker: dueDateChecker },
|
||||||
{ values: this.needsWorkFilters, checker: annotationFilterChecker, matchAll: true }
|
{ values: this.needsWorkFilters, checker: annotationFilterChecker, matchAll: true, checkerArgs: this.permissionsService }
|
||||||
];
|
];
|
||||||
this.detailsContainerFilters = {
|
this.detailsContainerFilters = {
|
||||||
statusFilters: this.statusFilters.map((f) => ({ ...f }))
|
statusFilters: this.statusFilters.map((f) => ({ ...f }))
|
||||||
|
|||||||
@ -53,7 +53,7 @@
|
|||||||
<div class="mt-24 legend" *ngIf="hasFiles">
|
<div class="mt-24 legend" *ngIf="hasFiles">
|
||||||
<div *ngFor="let filter of filters.needsWorkFilters" [class.active]="filter.checked" (click)="toggleFilter('needsWorkFilters', filter.key)">
|
<div *ngFor="let filter of filters.needsWorkFilters" [class.active]="filter.checked" (click)="toggleFilter('needsWorkFilters', filter.key)">
|
||||||
<redaction-annotation-icon *ngIf="filter.key !== 'none'" [typeValue]="appStateService.getDictionaryTypeValue(filter.key)"></redaction-annotation-icon>
|
<redaction-annotation-icon *ngIf="filter.key !== 'none'" [typeValue]="appStateService.getDictionaryTypeValue(filter.key)"></redaction-annotation-icon>
|
||||||
{{ 'project-overview.legend.' + filter.key | translate }}
|
{{ 'filter.' + filter.key | translate }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -122,7 +122,7 @@
|
|||||||
<div [class.disabled]="fileStatus.isPending || fileStatus.isProcessing" [class.error]="fileStatus.isError" class="table-item-title">
|
<div [class.disabled]="fileStatus.isPending || fileStatus.isProcessing" [class.error]="fileStatus.isError" class="table-item-title">
|
||||||
{{ fileStatus.filename }}
|
{{ fileStatus.filename }}
|
||||||
</div>
|
</div>
|
||||||
<span *ngIf="permissionsService.fileRequiresReanalysis(fileStatus)" class="pill" translate="project-overview.new-rule.label"></span>
|
<!-- <span *ngIf="permissionsService.fileRequiresReanalysis(fileStatus)" class="pill" translate="project-overview.new-rule.label"></span>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -191,6 +191,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// Needs work
|
// Needs work
|
||||||
this.appStateService.activeProject.files.forEach((file) => {
|
this.appStateService.activeProject.files.forEach((file) => {
|
||||||
|
if (this.permissionsService.fileRequiresReanalysis(file)) allDistinctNeedsWork.add('analysis');
|
||||||
if (file.hintsOnly) allDistinctNeedsWork.add('hint');
|
if (file.hintsOnly) allDistinctNeedsWork.add('hint');
|
||||||
if (file.hasRedactions) allDistinctNeedsWork.add('redaction');
|
if (file.hasRedactions) allDistinctNeedsWork.add('redaction');
|
||||||
if (file.hasRequests) allDistinctNeedsWork.add('suggestion');
|
if (file.hasRequests) allDistinctNeedsWork.add('suggestion');
|
||||||
@ -250,7 +251,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
|||||||
const filters = [
|
const filters = [
|
||||||
{ values: this.statusFilters, checker: keyChecker('status') },
|
{ values: this.statusFilters, checker: keyChecker('status') },
|
||||||
{ values: this.peopleFilters, checker: keyChecker('currentReviewer') },
|
{ values: this.peopleFilters, checker: keyChecker('currentReviewer') },
|
||||||
{ values: this.needsWorkFilters, checker: annotationFilterChecker, matchAll: true }
|
{ values: this.needsWorkFilters, checker: annotationFilterChecker, matchAll: true, checkerArgs: this.permissionsService }
|
||||||
];
|
];
|
||||||
this.displayedFiles = getFilteredEntities(this.appStateService.activeProject.files, filters);
|
this.displayedFiles = getFilteredEntities(this.appStateService.activeProject.files, filters);
|
||||||
this.detailsContainerFilters = {
|
this.detailsContainerFilters = {
|
||||||
|
|||||||
@ -390,6 +390,11 @@ export class AppStateService {
|
|||||||
type: 'add',
|
type: 'add',
|
||||||
virtual: true
|
virtual: true
|
||||||
};
|
};
|
||||||
|
this._dictionaryData['analysis'] = {
|
||||||
|
hexColor: '#dd4d50',
|
||||||
|
type: 'analysis',
|
||||||
|
virtual: true
|
||||||
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export class ProjectWrapper {
|
|||||||
hintsOnly?: boolean;
|
hintsOnly?: boolean;
|
||||||
hasRedactions?: boolean;
|
hasRedactions?: boolean;
|
||||||
hasRequests?: boolean;
|
hasRequests?: boolean;
|
||||||
|
hasNone?: boolean;
|
||||||
|
|
||||||
allFilesApproved?: boolean;
|
allFilesApproved?: boolean;
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ export class ProjectWrapper {
|
|||||||
this.hintsOnly = false;
|
this.hintsOnly = false;
|
||||||
this.hasRedactions = false;
|
this.hasRedactions = false;
|
||||||
this.hasRequests = false;
|
this.hasRequests = false;
|
||||||
|
this.hasNone = false;
|
||||||
this.allFilesApproved = true;
|
this.allFilesApproved = true;
|
||||||
this._files.forEach((f) => {
|
this._files.forEach((f) => {
|
||||||
this.hintsOnly = this.hintsOnly || f.hintsOnly;
|
this.hintsOnly = this.hintsOnly || f.hintsOnly;
|
||||||
@ -70,5 +72,6 @@ export class ProjectWrapper {
|
|||||||
this.hasRequests = this.hasRequests || f.hasRequests;
|
this.hasRequests = this.hasRequests || f.hasRequests;
|
||||||
this.allFilesApproved = this.allFilesApproved && f.isApproved;
|
this.allFilesApproved = this.allFilesApproved && f.isApproved;
|
||||||
});
|
});
|
||||||
|
this.hasNone = !this.hasRequests && !this.hasRedactions && !this.hintsOnly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -239,13 +239,7 @@
|
|||||||
},
|
},
|
||||||
"header": "Project Overview",
|
"header": "Project Overview",
|
||||||
"upload-document": "Upload Document",
|
"upload-document": "Upload Document",
|
||||||
"no-project": "Requested project: {{projectId}} does not exist! <a href='/ui/projects'>Back to Project Listing. <a/>",
|
"no-project": "Requested project: {{projectId}} does not exist! <a href='/ui/projects'>Back to Project Listing. <a/>"
|
||||||
"legend": {
|
|
||||||
"hint": "Hints only",
|
|
||||||
"redaction": "Redacted",
|
|
||||||
"suggestion": "Suggested Redaction",
|
|
||||||
"none": "No Annotations"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"file-preview": {
|
"file-preview": {
|
||||||
"show-redacted-view": "Show Redacted Preview",
|
"show-redacted-view": "Show Redacted Preview",
|
||||||
@ -317,6 +311,7 @@
|
|||||||
"hint": "Hints only",
|
"hint": "Hints only",
|
||||||
"redaction": "Redacted",
|
"redaction": "Redacted",
|
||||||
"suggestion": "Suggested Redaction",
|
"suggestion": "Suggested Redaction",
|
||||||
|
"analysis": "Re-analysis required",
|
||||||
"none": "No Annotations"
|
"none": "No Annotations"
|
||||||
},
|
},
|
||||||
"annotation-filter": {
|
"annotation-filter": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user