From aaf7590ed8049113370e525e34e973913c6cebe1 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 16 Mar 2025 21:00:29 -0700 Subject: [PATCH] Just save this [ci skip] --- .../filterable-dropdown.component.ts | 27 ++++++++++++++++--- .../filter-editor/filter-editor.component.ts | 22 ++++++++++++++- src-ui/src/app/data/filter-rule-type.ts | 2 ++ src-ui/src/app/utils/query-params.ts | 12 ++++++++- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts index 34320003e..5634eaa6f 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts +++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts @@ -12,6 +12,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { NgbDropdown, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { Subject, filter, takeUntil } from 'rxjs' +import { NEGATIVE_NULL_FILTER_VALUE } from 'src/app/data/filter-rule-type' import { MatchingModel } from 'src/app/data/matching-model' import { ObjectWithPermissions } from 'src/app/data/object-with-permissions' import { FilterPipe } from 'src/app/pipes/filter.pipe' @@ -129,6 +130,8 @@ export class FilterableDropdownSelectionModel { } toggle(id: number, fireEvent = true) { + console.log('toggling', id) + let state = this.temporarySelectionStates.get(id) if ( state == undefined || @@ -241,6 +244,8 @@ export class FilterableDropdownSelectionModel { } set intersection(intersection: Intersection) { + console.log('setting intersection', intersection) + this.temporaryIntersection = intersection } @@ -304,9 +309,20 @@ export class FilterableDropdownSelectionModel { } isNoneSelected() { + console.log(this.intersection) + + console.log( + this.selectionSize(), + this.get(null), + this.get(NEGATIVE_NULL_FILTER_VALUE) + ) + return ( - this.selectionSize() == 1 && - this.get(null) == ToggleableItemState.Selected + (this.selectionSize() == 1 && + this.get(null) == ToggleableItemState.Selected) || + (this.selectionSize() > 1 && + this.get(NEGATIVE_NULL_FILTER_VALUE) == ToggleableItemState.Selected && + this.intersection == Intersection.Exclude) ) } @@ -390,7 +406,10 @@ export class FilterableDropdownComponent this._selectionModel.items = Array.from(items) this._selectionModel.items.unshift({ name: $localize`:Filter drop down element to filter for documents with no correspondent/type/tag assigned:Not assigned`, - id: null, + id: + this.selectionModel.intersection === Intersection.Include + ? null + : NEGATIVE_NULL_FILTER_VALUE, }) } } @@ -484,7 +503,7 @@ export class FilterableDropdownComponent return this.manyToOne ? this.selectionModel.selectionSize() > 1 && this.selectionModel.getExcludedItems().length == 0 - : !this.selectionModel.isNoneSelected() + : true } get name(): string { diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts index debd7b4b3..dc96b6a8f 100644 --- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts +++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts @@ -75,6 +75,7 @@ import { FILTER_STORAGE_PATH, FILTER_TITLE, FILTER_TITLE_CONTENT, + NEGATIVE_NULL_FILTER_VALUE, } from 'src/app/data/filter-rule-type' import { StoragePath } from 'src/app/data/storage-path' import { Tag } from 'src/app/data/tag' @@ -551,6 +552,16 @@ export class FilterEditorComponent ) break case FILTER_CORRESPONDENT: + this.correspondentSelectionModel.intersection = + rule.value == NEGATIVE_NULL_FILTER_VALUE.toString() + ? Intersection.Exclude + : Intersection.Include + this.correspondentSelectionModel.set( + rule.value ? +rule.value : null, + ToggleableItemState.Selected, + false + ) + break case FILTER_HAS_CORRESPONDENT_ANY: this.correspondentSelectionModel.logicalOperator = LogicalOperator.Or this.correspondentSelectionModel.intersection = Intersection.Include @@ -810,7 +821,16 @@ export class FilterEditorComponent }) } if (this.correspondentSelectionModel.isNoneSelected()) { - filterRules.push({ rule_type: FILTER_CORRESPONDENT, value: null }) + if ( + this.correspondentSelectionModel.intersection == Intersection.Exclude + ) { + filterRules.push({ + rule_type: FILTER_CORRESPONDENT, + value: NEGATIVE_NULL_FILTER_VALUE.toString(), + }) + } else { + filterRules.push({ rule_type: FILTER_CORRESPONDENT, value: null }) + } } else { this.correspondentSelectionModel .getSelectedItems() diff --git a/src-ui/src/app/data/filter-rule-type.ts b/src-ui/src/app/data/filter-rule-type.ts index bb2bf762c..7f0f0d56d 100644 --- a/src-ui/src/app/data/filter-rule-type.ts +++ b/src-ui/src/app/data/filter-rule-type.ts @@ -1,5 +1,7 @@ import { DataType } from './datatype' +export const NEGATIVE_NULL_FILTER_VALUE = -1 + // These correspond to src/documents/models.py and changes here require a DB migration (and vice versa) export const FILTER_TITLE = 0 export const FILTER_CONTENT = 1 diff --git a/src-ui/src/app/utils/query-params.ts b/src-ui/src/app/utils/query-params.ts index d90167c5b..27716cc2d 100644 --- a/src-ui/src/app/utils/query-params.ts +++ b/src-ui/src/app/utils/query-params.ts @@ -10,6 +10,7 @@ import { FILTER_HAS_CUSTOM_FIELDS_ANY, FILTER_RULE_TYPES, FilterRuleType, + NEGATIVE_NULL_FILTER_VALUE, } from '../data/filter-rule-type' import { ListViewState } from '../services/document-list-view.service' @@ -113,6 +114,10 @@ export function filterRulesFromQueryParams( rt.isnull_filtervar == filterQueryParamName ) const isNullRuleType = rule_type.isnull_filtervar == filterQueryParamName + const nullRuleValue = + queryParams.get(filterQueryParamName) == '1' + ? null + : NEGATIVE_NULL_FILTER_VALUE.toString() const valueURIComponent: string = queryParams.get(filterQueryParamName) const filterQueryParamValues: string[] = rule_type.multi ? valueURIComponent.split(',') @@ -125,7 +130,7 @@ export function filterRulesFromQueryParams( val = val.replace('1', 'true').replace('0', 'false') return { rule_type: rule_type.id, - value: isNullRuleType ? null : val, + value: isNullRuleType ? nullRuleValue : val, } }) ) @@ -143,6 +148,11 @@ export function queryParamsFromFilterRules(filterRules: FilterRule[]): Params { let ruleType = FILTER_RULE_TYPES.find((t) => t.id == rule.rule_type) if (ruleType.isnull_filtervar && rule.value == null) { params[ruleType.isnull_filtervar] = 1 + } else if ( + ruleType.isnull_filtervar && + rule.value == NEGATIVE_NULL_FILTER_VALUE.toString() + ) { + params[ruleType.isnull_filtervar] = 0 } else if (ruleType.multi) { params[ruleType.filtervar] = params[ruleType.filtervar] ? params[ruleType.filtervar] + ',' + rule.value