diff --git a/apps/red-ui/src/app/common/filter/model/filter.model.ts b/apps/red-ui/src/app/common/filter/model/filter.model.ts index 908a0af47..13396e7b1 100644 --- a/apps/red-ui/src/app/common/filter/model/filter.model.ts +++ b/apps/red-ui/src/app/common/filter/model/filter.model.ts @@ -5,5 +5,6 @@ export interface FilterModel { indeterminate?: boolean; expanded?: boolean; topLevelFilter?: boolean; + matches?: number; filters?: FilterModel[]; } diff --git a/apps/red-ui/src/app/common/filter/utils/filter-utils.ts b/apps/red-ui/src/app/common/filter/utils/filter-utils.ts index f7fc4b4a1..194bbb5cf 100644 --- a/apps/red-ui/src/app/common/filter/utils/filter-utils.ts +++ b/apps/red-ui/src/app/common/filter/utils/filter-utils.ts @@ -17,13 +17,15 @@ export function handleFilterDelta(oldFilters: FilterModel[], newFilters: FilterM const newFiltersDelta = {}; for (const newFilter of newFilters) { const oldFilter = oldFilters.find((f) => f.key === newFilter.key); - if (!oldFilter) { + if (!oldFilter || oldFilter.matches !== newFilter.matches) { newFiltersDelta[newFilter.key] = {}; newFilter.filters.forEach((filter) => (newFiltersDelta[newFilter.key][filter.key] = {})); - } else { + } + + if (!oldFilter) { for (const childFilter of newFilter.filters) { const oldFilterChild = oldFilter.filters.find((f) => f.key === childFilter.key); - if (!oldFilterChild) { + if (!oldFilterChild || oldFilterChild.matches !== childFilter.matches) { if (!newFiltersDelta[newFilter.key]) { newFiltersDelta[newFilter.key] = {}; } diff --git a/apps/red-ui/src/app/common/service/annotation-actions.service.ts b/apps/red-ui/src/app/common/service/annotation-actions.service.ts index 01d7faeda..3cba9018f 100644 --- a/apps/red-ui/src/app/common/service/annotation-actions.service.ts +++ b/apps/red-ui/src/app/common/service/annotation-actions.service.ts @@ -26,13 +26,13 @@ export class AnnotationActionsService { // i can reject whatever i may not undo return ( !this.canUndoAnnotation(annotation) && - ((this.canAcceptSuggestion && !annotation.isDeclinedSuggestion) || (annotation.isModifyDictionary && !annotation.isDeclinedSuggestion)) + ((this.canAcceptSuggestion(annotation) && !annotation.isDeclinedSuggestion) || (annotation.isModifyDictionary && !annotation.isDeclinedSuggestion)) ); } public canDirectlySuggestToRemoveAnnotation(annotation: AnnotationWrapper): boolean { return ( - (annotation.isHint || (annotation.isManual && this._permissionsService.isManagerAndOwner() && !this.canUndoAnnotation)) && + (annotation.isHint || (annotation.isManual && this._permissionsService.isManagerAndOwner() && !this.canUndoAnnotation(annotation))) && !annotation.isRecommendation ); } diff --git a/apps/red-ui/src/app/screens/file/service/annotation-processing.service.ts b/apps/red-ui/src/app/screens/file/service/annotation-processing.service.ts index a4921444b..b689f23b2 100644 --- a/apps/red-ui/src/app/screens/file/service/annotation-processing.service.ts +++ b/apps/red-ui/src/app/screens/file/service/annotation-processing.service.ts @@ -12,43 +12,58 @@ export class AnnotationProcessingService { constructor(private readonly _appStateService: AppStateService) {} getAnnotationFilter(annotations: AnnotationWrapper[]): FilterModel[] { + const filterMap = new Map(); const filters: FilterModel[] = []; - const availableAnnotationTypes = {}; annotations?.forEach((a) => { - if (a.superType === 'hint' || a.superType === 'redaction') { - const entry = availableAnnotationTypes[a.superType]; - if (!entry) { - availableAnnotationTypes[a.superType] = new Set([a.dictionary]); - } else { - entry.add(a.dictionary); - } + const topLevelFilter = a.superType !== 'hint' && a.superType !== 'redaction'; + const key = topLevelFilter ? a.superType : a.superType + a.dictionary; + const filter = filterMap.get(key); + if (filter) { + filter.matches += 1; } else { - availableAnnotationTypes[a.superType] = new Set(); + // top level filter + if (topLevelFilter) { + this._createParentFilter(key, filterMap, filters); + } else { + let parentFilter = filterMap.get(a.superType); + if (!parentFilter) { + parentFilter = this._createParentFilter(a.superType, filterMap, filters); + } + const childFilter = { key: a.dictionary, checked: false, filters: [], matches: 1 }; + filterMap.set(key, childFilter); + parentFilter.filters.push(childFilter); + } } }); - for (const key of Object.keys(availableAnnotationTypes)) { - const filter: FilterModel = { - key: key, - topLevelFilter: true, - label: 'annotation-type.' + key, - filters: Array.from(availableAnnotationTypes[key]).map((dc: string) => { - // const defaultFilter = this._appStateService.dictionaryData[dc]?.defaultFilter; - return { key: dc, checked: false, filters: [] }; - }) - }; + for (const filter of filters) { filter.filters.sort((a, b) => a.key.localeCompare(b.key)); handleCheckedValue(filter); if (filter.checked || filter.indeterminate) { filter.expanded = true; } - filters.push(filter); + if (filter.filters.length > 0) { + filter.matches = filter.filters.reduce((a, b) => a + b.matches, 0); + } } return filters.sort((a, b) => SuperTypeSorter[a.key] - SuperTypeSorter[b.key]); } + private _createParentFilter(key: string, filterMap: Map, filters: FilterModel[]) { + const filter: FilterModel = { + key: key, + topLevelFilter: true, + matches: 1, + label: 'annotation-type.' + key, + filters: [] + }; + filterMap.set(key, filter); + filters.push(filter); + return filter; + } + filterAndGroupAnnotations(annotations: AnnotationWrapper[], filters: FilterModel[]): { [key: number]: { annotations: AnnotationWrapper[] } } { const obj = {};