selection model

This commit is contained in:
jonaswinkler 2020-12-28 00:52:28 +01:00
parent b8e7506de4
commit 4fb5dce5e7
5 changed files with 87 additions and 53 deletions

View File

@ -20,8 +20,8 @@
</div>
</div>
<div *ngIf="selectionModel.items" class="items">
<ng-container *ngFor="let toggleableItem of selectionModel.items | filter: filterText">
<app-toggleable-dropdown-button [toggleableItem]="toggleableItem" (toggle)="selectionModel.toggle(toggleableItem.item)"></app-toggleable-dropdown-button>
<ng-container *ngFor="let item of selectionModel.items | filter: filterText">
<app-toggleable-dropdown-button [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)"></app-toggleable-dropdown-button>
</ng-container>
</div>
<button *ngIf="type == types.Editing" class="list-group-item list-group-item-action bg-light" (click)="dropdown.close()" [disabled]="!hasBeenToggled || (toggleableItems | filter: filterText).length == 0">

View File

@ -4,6 +4,7 @@ import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
import { ToggleableItem, ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component';
import { MatchingModel } from 'src/app/data/matching-model';
import { Subject } from 'rxjs';
import { ThrowStmt } from '@angular/compiler';
export enum FilterableDropdownType {
Filtering = 'filtering',
@ -16,39 +17,56 @@ export class FilterableDropdownSelectionModel {
multiple = false
items: ToggleableItem[] = []
items: MatchingModel[] = []
getSelected() {
return this.items.filter(i => i.state == ToggleableItemState.Selected).map(i => i.item)
selection = new Map<number, ToggleableItemState>()
getSelectedItems() {
return this.items.filter(i => this.selection.get(i.id) == ToggleableItemState.Selected)
}
toggle(item: MatchingModel, fireEvent = true) {
console.log("TOGGLE TAG")
let toggleableItem = this.items.find(i => i.item == item)
console.log(toggleableItem)
if (toggleableItem) {
if (toggleableItem.state == ToggleableItemState.Selected) {
toggleableItem.state = ToggleableItemState.NotSelected
} else {
this.items.forEach(i => {
if (i.item == item) {
i.state = ToggleableItemState.Selected
} else if (!this.multiple) {
i.state = ToggleableItemState.NotSelected
}
})
}
if (fireEvent) {
this.changed.next(this)
}
set(id: number, state: ToggleableItemState, fireEvent = true) {
this.selection.set(id, state)
if (fireEvent) {
this.changed.next(this)
}
}
toggle(id: number, fireEvent = true) {
let state = this.selection.get(id)
if (state == null || state != ToggleableItemState.Selected) {
this.selection.set(id, ToggleableItemState.Selected)
} else if (state == ToggleableItemState.Selected) {
this.selection.set(id, ToggleableItemState.NotSelected)
}
if (!this.multiple) {
for (let key of this.selection.keys()) {
if (key != id) {
this.selection.set(key, ToggleableItemState.NotSelected)
}
}
}
if (fireEvent) {
this.changed.next(this)
}
}
get(id: number) {
return this.selection.get(id) || ToggleableItemState.NotSelected
}
selectionSize() {
return this.getSelected().length
return this.getSelectedItems().length
}
clear(fireEvent = true) {
this.selection.clear()
if (fireEvent) {
this.changed.next(this)
}
}
}
@ -67,14 +85,12 @@ export class FilterableDropdownComponent {
@Input()
set items(items: MatchingModel[]) {
if (items) {
this._selectionModel.items = items.map(i => {
return {item: i, state: ToggleableItemState.NotSelected, count: i.document_count}
})
this._selectionModel.items = items
}
}
get items(): MatchingModel[] {
return this._selectionModel.items.map(i => i.item)
return this._selectionModel.items
}
_selectionModel = new FilterableDropdownSelectionModel()

View File

@ -5,8 +5,8 @@
</svg>
</div>
<div class="mr-1">
<app-tag *ngIf="isTag; else displayName" [tag]="toggleableItem?.item" [clickable]="true" linkTitle="Filter by tag"></app-tag>
<ng-template #displayName><small>{{toggleableItem?.item.name}}</small></ng-template>
<app-tag *ngIf="isTag; else displayName" [tag]="item" [clickable]="true" linkTitle="Filter by tag"></app-tag>
<ng-template #displayName><small>{{item.name}}</small></ng-template>
</div>
<div class="badge badge-light rounded-pill ml-auto mr-1">{{toggleableItem?.count}}</div>
<div class="badge badge-light rounded-pill ml-auto mr-1">{{item.document_count}}</div>
</button>

View File

@ -21,13 +21,19 @@ export enum ToggleableItemState {
export class ToggleableDropdownButtonComponent {
@Input()
toggleableItem: ToggleableItem
item: MatchingModel
@Input()
state: ToggleableItemState
@Input()
count: number
@Output()
toggle = new EventEmitter()
get isTag(): boolean {
return 'is_inbox_tag' in this.toggleableItem?.item // ~ this.item instanceof PaperlessTag
return 'is_inbox_tag' in this.item
}
toggleItem(): void {
@ -35,9 +41,9 @@ export class ToggleableDropdownButtonComponent {
}
getSelectedIconName() {
if (this.toggleableItem?.state == ToggleableItemState.Selected) {
if (this.state == ToggleableItemState.Selected) {
return "check"
} else if (this.toggleableItem?.state == ToggleableItemState.PartiallySelected) {
} else if (this.state == ToggleableItemState.PartiallySelected) {
return "dash"
} else {
return ""

View File

@ -3,13 +3,14 @@ import { PaperlessTag } from 'src/app/data/paperless-tag';
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
import { Subject, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged, filter, flatMap, mergeMap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { DocumentTypeService } from 'src/app/services/rest/document-type.service';
import { TagService } from 'src/app/services/rest/tag.service';
import { CorrespondentService } from 'src/app/services/rest/correspondent.service';
import { FilterRule } from 'src/app/data/filter-rule';
import { FILTER_ADDED_AFTER, FILTER_ADDED_BEFORE, FILTER_CORRESPONDENT, FILTER_CREATED_AFTER, FILTER_CREATED_BEFORE, FILTER_DOCUMENT_TYPE, FILTER_HAS_TAG, FILTER_RULE_TYPES, FILTER_TITLE } from 'src/app/data/filter-rule-type';
import { FILTER_ADDED_AFTER, FILTER_ADDED_BEFORE, FILTER_CORRESPONDENT, FILTER_CREATED_AFTER, FILTER_CREATED_BEFORE, FILTER_DOCUMENT_TYPE, FILTER_HAS_TAG, FILTER_TITLE } from 'src/app/data/filter-rule-type';
import { FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component';
import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component';
@Component({
selector: 'app-filter-editor',
@ -61,7 +62,6 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
@Input()
set filterRules (value: FilterRule[]) {
console.log("SET FILTER RULES")
value.forEach(rule => {
switch (rule.rule_type) {
case FILTER_TITLE:
@ -79,31 +79,34 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
case FILTER_ADDED_BEFORE:
this.dateAddedBefore = rule.value
break
case FILTER_HAS_TAG:
this.tagSelectionModel.set(+rule.value, ToggleableItemState.Selected, false)
break
case FILTER_CORRESPONDENT:
this.correspondentSelectionModel.set(+rule.value, ToggleableItemState.Selected, false)
break
case FILTER_DOCUMENT_TYPE:
this.documentTypeSelectionModel.set(+rule.value, ToggleableItemState.Selected, false)
break
}
})
this.tagService.getCachedMany(value.filter(v => v.rule_type == FILTER_HAS_TAG).map(rule => +rule.value)).subscribe(tags => {
console.log(tags)
tags.forEach(tag => this.tagSelectionModel.toggle(tag, false))
})
}
@Output()
filterRulesChange = new EventEmitter<FilterRule[]>()
updateRules() {
console.log("UPDATE RULES!!!")
let filterRules: FilterRule[] = []
if (this._titleFilter) {
filterRules.push({rule_type: FILTER_TITLE, value: this._titleFilter})
}
this.tagSelectionModel.getSelected().forEach(tag => {
this.tagSelectionModel.getSelectedItems().forEach(tag => {
filterRules.push({rule_type: FILTER_HAS_TAG, value: tag.id.toString()})
})
this.correspondentSelectionModel.getSelected().forEach(correspondent => {
this.correspondentSelectionModel.getSelectedItems().forEach(correspondent => {
filterRules.push({rule_type: FILTER_CORRESPONDENT, value: correspondent.id.toString()})
})
this.documentTypeSelectionModel.getSelected().forEach(documentType => {
this.documentTypeSelectionModel.getSelectedItems().forEach(documentType => {
filterRules.push({rule_type: FILTER_DOCUMENT_TYPE, value: documentType.id.toString()})
})
if (this.dateCreatedBefore) {
@ -118,13 +121,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
if (this.dateAddedAfter) {
filterRules.push({rule_type: FILTER_ADDED_AFTER, value: this.dateAddedAfter})
}
console.log(filterRules)
this.filterRulesChange.next(filterRules)
}
hasFilters() {
return this._titleFilter ||
this.dateCreatedAfter || this.dateAddedBefore || this.dateCreatedAfter || this.dateCreatedBefore ||
this.dateAddedAfter || this.dateAddedBefore || this.dateCreatedAfter || this.dateCreatedBefore ||
this.tagSelectionModel.selectionSize() || this.correspondentSelectionModel.selectionSize() || this.documentTypeSelectionModel.selectionSize()
}
@ -161,16 +163,26 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
clearSelected() {
this._titleFilter = ""
this.tagSelectionModel.clear(false)
this.documentTypeSelectionModel.clear(false)
this.correspondentSelectionModel.clear(false)
this.dateAddedBefore = null
this.dateAddedAfter = null
this.dateCreatedBefore = null
this.dateCreatedAfter = null
this.updateRules()
}
toggleTag(tagId: number) {
this.tagSelectionModel.toggle(tagId)
}
toggleCorrespondent(correspondentId: number) {
this.correspondentSelectionModel.toggle(correspondentId)
}
toggleDocumentType(documentTypeId: number) {
this.documentTypeSelectionModel.toggle(documentTypeId)
}
}