Refactor filters
This commit is contained in:
parent
9bdbbdb0ef
commit
4ce1592207
@ -1,4 +1,7 @@
|
||||
import { FilterModel } from '../model/filter.model';
|
||||
import { FileStatusWrapper } from '../../../screens/file/model/file-status.wrapper';
|
||||
import * as moment from 'moment';
|
||||
import { ProjectWrapper } from '../../../state/app-state.service';
|
||||
|
||||
export function handleCheckedValue(filter: FilterModel) {
|
||||
if (filter.filters && filter.filters.length) {
|
||||
@ -12,3 +15,59 @@ export function handleCheckedValue(filter: FilterModel) {
|
||||
filter.indeterminate = false;
|
||||
}
|
||||
}
|
||||
|
||||
export function checkFilter(entity: any, filters: FilterModel[], validate: Function) {
|
||||
const hasChecked = filters.find((f) => f.checked);
|
||||
if (!hasChecked) {
|
||||
return true;
|
||||
}
|
||||
let filterMatched = false;
|
||||
for (const filter of filters) {
|
||||
if (filter.checked && validate(entity, filter)) {
|
||||
filterMatched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
}
|
||||
|
||||
export const keyChecker = (key: string) => (entity: any, filter: FilterModel) =>
|
||||
entity[key] === filter.key;
|
||||
|
||||
export const annotationFilterChecker = (f: FileStatusWrapper, filter: FilterModel) => {
|
||||
const getter = 'has' + filter.key[0].toUpperCase() + filter.key.slice(1);
|
||||
return f[getter];
|
||||
};
|
||||
|
||||
export const fileAddedFilterChecker = (f: FileStatusWrapper, filter: FilterModel) =>
|
||||
moment(f.added).format('DD/MM/YYYY') === filter.key;
|
||||
|
||||
export const projectStatusChecker = (pw: ProjectWrapper, filter: FilterModel) =>
|
||||
pw.hasStatus(filter.key);
|
||||
|
||||
export const projectMemberChecker = (pw: ProjectWrapper, filter: FilterModel) => {
|
||||
return pw.hasMember(filter.key);
|
||||
};
|
||||
|
||||
export const dueDateChecker = (pw: ProjectWrapper, filter: FilterModel) =>
|
||||
pw.dueDateMatches(filter.key);
|
||||
|
||||
export const addedDateChecker = (pw: ProjectWrapper, filter: FilterModel) =>
|
||||
pw.addedDateMatches(filter.key);
|
||||
|
||||
export function getFilteredEntities(
|
||||
entities: any[],
|
||||
filters: { values: FilterModel[]; checker: Function }[]
|
||||
) {
|
||||
const filteredEntities = [];
|
||||
for (const entity of entities) {
|
||||
let add = true;
|
||||
for (const filter of filters) {
|
||||
add = add && checkFilter(entity, filter.values, filter.checker);
|
||||
}
|
||||
if (add) {
|
||||
filteredEntities.push(entity);
|
||||
}
|
||||
}
|
||||
return filteredEntities;
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ export class AnnotationIconComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.typeValue?.type === 'request') {
|
||||
let styleSheet = document.styleSheets[0];
|
||||
const styleSheet = document.styleSheets[0];
|
||||
styleSheet.insertRule(
|
||||
`.request:after { border-top-color: ${this.typeValue.hexColor} !important; }`,
|
||||
styleSheet.cssRules.length
|
||||
|
||||
@ -31,6 +31,7 @@ export class IconsModule {
|
||||
'lightning',
|
||||
'logout',
|
||||
'menu',
|
||||
'needs-work',
|
||||
'pages',
|
||||
'plus',
|
||||
'preview',
|
||||
|
||||
@ -8,6 +8,13 @@ import { DialogService } from '../../dialogs/dialog.service';
|
||||
import { FilterModel } from '../../common/filter/model/filter.model';
|
||||
import * as moment from 'moment';
|
||||
import { SortingComponent, SortingOption } from '../../components/sorting/sorting.component';
|
||||
import {
|
||||
addedDateChecker,
|
||||
dueDateChecker,
|
||||
getFilteredEntities,
|
||||
projectMemberChecker,
|
||||
projectStatusChecker
|
||||
} from '../../common/filter/utils/filter-utils';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-listing-screen',
|
||||
@ -205,59 +212,17 @@ export class ProjectListingScreenComponent implements OnInit {
|
||||
}
|
||||
|
||||
private _filterProjects() {
|
||||
const filteredProjects = [];
|
||||
const filters = [
|
||||
{ values: this.statusFilters, checker: projectStatusChecker },
|
||||
{ values: this.peopleFilters, checker: projectMemberChecker },
|
||||
{ values: this.dueDateFilters, checker: dueDateChecker },
|
||||
{ values: this.addedDateFilters, checker: addedDateChecker }
|
||||
];
|
||||
|
||||
for (const project of this.appStateService.allProjects) {
|
||||
const statusFilterMatched = this._checkFilter(
|
||||
project,
|
||||
this.statusFilters,
|
||||
(pw: ProjectWrapper, filter: FilterModel) => pw.hasStatus(filter.key)
|
||||
);
|
||||
const peopleFilterMatched = this._checkFilter(
|
||||
project,
|
||||
this.peopleFilters,
|
||||
(pw: ProjectWrapper, filter: FilterModel) => pw.hasMember(filter.key)
|
||||
);
|
||||
const dueDateFilterMatched = this._checkFilter(
|
||||
project,
|
||||
this.dueDateFilters,
|
||||
(pw: ProjectWrapper, filter: FilterModel) => pw.dueDateMatches(filter.key)
|
||||
);
|
||||
const addedFilterMatched = this._checkFilter(
|
||||
project,
|
||||
this.addedDateFilters,
|
||||
(pw: ProjectWrapper, filter: FilterModel) => pw.addedDateMatches(filter.key)
|
||||
);
|
||||
|
||||
if (
|
||||
statusFilterMatched &&
|
||||
peopleFilterMatched &&
|
||||
addedFilterMatched &&
|
||||
dueDateFilterMatched
|
||||
) {
|
||||
filteredProjects.push(project);
|
||||
}
|
||||
}
|
||||
|
||||
this.displayedProjects = filteredProjects;
|
||||
this.displayedProjects = getFilteredEntities(this.appStateService.allProjects, filters);
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
private _checkFilter(project: ProjectWrapper, filters: FilterModel[], validate: Function) {
|
||||
const hasChecked = filters.find((f) => f.checked);
|
||||
if (!hasChecked) {
|
||||
return true;
|
||||
}
|
||||
let filterMatched = false;
|
||||
for (const filter of filters) {
|
||||
if (filter.checked && validate(project, filter)) {
|
||||
filterMatched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
}
|
||||
|
||||
public toggleProjectSelected($event: MouseEvent, pw: ProjectWrapper) {
|
||||
$event.stopPropagation();
|
||||
const idx = this._selectedProjectIds.indexOf(pw.project.projectId);
|
||||
|
||||
@ -34,6 +34,13 @@
|
||||
[hasArrow]="false"
|
||||
[icon]="'red:calendar'"
|
||||
></redaction-filter>
|
||||
<redaction-filter
|
||||
(filtersChanged)="filtersChanged()"
|
||||
[filterLabel]="'filters.needs-work'"
|
||||
[filters]="needsWorkFilters"
|
||||
[hasArrow]="false"
|
||||
[icon]="'red:needs-work'"
|
||||
></redaction-filter>
|
||||
<!-- <button mat-button translate="filters.project">-->
|
||||
<!-- <mat-icon svgIcon="red:folder"></mat-icon>-->
|
||||
<!-- </button>-->
|
||||
|
||||
@ -22,6 +22,12 @@ import * as moment from 'moment';
|
||||
import { SortingComponent, SortingOption } from '../../components/sorting/sorting.component';
|
||||
import { ProjectDetailsComponent } from './project-details/project-details.component';
|
||||
import { FileStatusWrapper } from '../file/model/file-status.wrapper';
|
||||
import {
|
||||
annotationFilterChecker,
|
||||
fileAddedFilterChecker,
|
||||
getFilteredEntities,
|
||||
keyChecker
|
||||
} from '../../common/filter/utils/filter-utils';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-overview-screen',
|
||||
@ -35,6 +41,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
public statusFilters: FilterModel[];
|
||||
public peopleFilters: FilterModel[];
|
||||
public addedDateFilters: FilterModel[];
|
||||
public needsWorkFilters: FilterModel[];
|
||||
|
||||
public displayedFiles: FileStatusWrapper[] = [];
|
||||
|
||||
@ -260,6 +267,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
const allDistinctFileStatusWrapper = new Set<string>();
|
||||
const allDistinctPeople = new Set<string>();
|
||||
const allDistinctAddedDates = new Set<string>();
|
||||
const allDistinctNeedsWork = new Set<string>();
|
||||
|
||||
// All people
|
||||
this.appStateService.activeProject.project.memberIds.forEach((memberId) =>
|
||||
@ -276,6 +284,13 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
allDistinctAddedDates.add(moment(file.added).format('DD/MM/YYYY'))
|
||||
);
|
||||
|
||||
// Needs work
|
||||
this.appStateService.activeProject.files.forEach((file) => {
|
||||
if (file.hasHints) allDistinctNeedsWork.add('hints');
|
||||
if (file.hasRedactions) allDistinctNeedsWork.add('redactions');
|
||||
if (file.hasRequests) allDistinctNeedsWork.add('requests');
|
||||
});
|
||||
|
||||
this.statusFilters = [];
|
||||
allDistinctFileStatusWrapper.forEach((status) => {
|
||||
this.statusFilters.push({
|
||||
@ -299,6 +314,14 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
label: date
|
||||
});
|
||||
});
|
||||
|
||||
this.needsWorkFilters = [];
|
||||
allDistinctNeedsWork.forEach((type) => {
|
||||
this.needsWorkFilters.push({
|
||||
key: type,
|
||||
label: this._translateService.instant('filter.' + type)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
filtersChanged() {
|
||||
@ -306,52 +329,19 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private _filterFiles() {
|
||||
const filteredFiles = [];
|
||||
|
||||
for (const file of this.appStateService.activeProject.files) {
|
||||
const statusFilterMatched = this._checkFilter(
|
||||
file,
|
||||
this.statusFilters,
|
||||
(f: FileStatusWrapper, filter: FilterModel) => f.status === filter.key
|
||||
);
|
||||
|
||||
const peopleFilterMatched = this._checkFilter(
|
||||
file,
|
||||
this.peopleFilters,
|
||||
(f: FileStatusWrapper, filter: FilterModel) => f.currentReviewer === filter.key
|
||||
);
|
||||
|
||||
const addedFilterMatched = this._checkFilter(
|
||||
file,
|
||||
this.addedDateFilters,
|
||||
(f: FileStatusWrapper, filter: FilterModel) =>
|
||||
moment(f.added).format('DD/MM/YYYY') === filter.key
|
||||
);
|
||||
|
||||
if (statusFilterMatched && peopleFilterMatched && addedFilterMatched) {
|
||||
filteredFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
this.displayedFiles = filteredFiles;
|
||||
const filters = [
|
||||
{ values: this.statusFilters, checker: keyChecker('status') },
|
||||
{ values: this.peopleFilters, checker: keyChecker('currentReviewer') },
|
||||
{ values: this.addedDateFilters, checker: fileAddedFilterChecker },
|
||||
{ values: this.needsWorkFilters, checker: annotationFilterChecker }
|
||||
];
|
||||
this.displayedFiles = getFilteredEntities(
|
||||
this.appStateService.activeProject.files,
|
||||
filters
|
||||
);
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
private _checkFilter(file: FileStatusWrapper, filters: FilterModel[], validate: Function) {
|
||||
const hasChecked = filters.find((f) => f.checked);
|
||||
if (!hasChecked) {
|
||||
return true;
|
||||
}
|
||||
let filterMatched = false;
|
||||
for (const filter of filters) {
|
||||
if (filter.checked && validate(file, filter)) {
|
||||
filterMatched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
}
|
||||
|
||||
requestApprovalOrApproveFile($event: MouseEvent, fileStatusWrapper: FileStatusWrapper) {
|
||||
$event.stopPropagation();
|
||||
this._fileActionService.requestApprovalOrApproveFile(fileStatusWrapper).subscribe(() => {
|
||||
|
||||
@ -89,7 +89,8 @@
|
||||
"due-date": "Due Date",
|
||||
"created-on": "Created On",
|
||||
"project": "Project",
|
||||
"document": "Document"
|
||||
"document": "Document",
|
||||
"needs-work": "Needs Work"
|
||||
},
|
||||
"project-listing": {
|
||||
"report": {
|
||||
@ -295,7 +296,11 @@
|
||||
"dictionary": "Dictionary",
|
||||
"content": "Content",
|
||||
"page": "Page",
|
||||
"filter": {},
|
||||
"filter": {
|
||||
"hints": "Hints",
|
||||
"redactions": "Redactions",
|
||||
"requests": "Requests"
|
||||
},
|
||||
"annotation-filter": {
|
||||
"super-type": {
|
||||
"redaction": "Redaction",
|
||||
|
||||
7
apps/red-ui/src/assets/icons/general/needs-work.svg
Normal file
7
apps/red-ui/src/assets/icons/general/needs-work.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Needs work</title>
|
||||
<g id="Needs-work" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<path d="M100,90 L100,100 L39,100 L39,90 L100,90 Z M70,0 L70,45 L60,45 L60,10 L10,10 L10,80 L30,80 L30,90 L0,90 L0,0 L70,0 Z M86,72 L86,82 L39,82 L39,72 L86,72 Z M62,54 L62,64 L39,64 L39,54 L62,54 Z" id="Combined-Shape" fill="currentColor" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 597 B |
Loading…
x
Reference in New Issue
Block a user