Refactor editor and filterable dropdowns to be common components in anticipation of bulk editor

This commit is contained in:
Michael Shamoon 2020-12-18 16:03:52 -08:00
parent fbb2da42dc
commit 55a6dca373
20 changed files with 105 additions and 105 deletions

View File

@ -26,10 +26,10 @@ import { ResultHighlightComponent } from './components/search/result-highlight/r
import { PageHeaderComponent } from './components/common/page-header/page-header.component';
import { AppFrameComponent } from './components/app-frame/app-frame.component';
import { ToastsComponent } from './components/common/toasts/toasts.component';
import { FilterEditorComponent } from './components/filter-editor/filter-editor.component';
import { FilterDropdownComponent } from './components/filter-editor/filter-dropdown/filter-dropdown.component';
import { FilterDropdownButtonComponent } from './components/filter-editor/filter-dropdown/filter-dropdown-button/filter-dropdown-button.component';
import { FilterDropdownDateComponent } from './components/filter-editor/filter-dropdown-date/filter-dropdown-date.component';
import { FilterEditorComponent } from './components/document-list/filter-editor/filter-editor.component';
import { FilterableDropdownComponent } from './components/common/filterable-dropdown/filterable-dropdown.component';
import { FilterableDropdownButtonComponent } from './components/common/filterable-dropdown/filterable-dropdown-button/filterable-dropdown-button.component';
import { DateDropdownComponent } from './components/common/date-dropdown/date-dropdown.component';
import { DocumentCardLargeComponent } from './components/document-list/document-card-large/document-card-large.component';
import { DocumentCardSmallComponent } from './components/document-list/document-card-small/document-card-small.component';
import { BulkEditorComponent } from './components/document-list/bulk-editor/bulk-editor.component';
@ -81,9 +81,9 @@ import { NgSelectModule } from '@ng-select/ng-select';
AppFrameComponent,
ToastsComponent,
FilterEditorComponent,
FilterDropdownComponent,
FilterDropdownButtonComponent,
FilterDropdownDateComponent,
FilterableDropdownComponent,
FilterableDropdownButtonComponent,
DateDropdownComponent,
DocumentCardLargeComponent,
DocumentCardSmallComponent,
BulkEditorComponent,

View File

@ -2,7 +2,7 @@
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="dateBefore || dateAfter ? 'btn-primary' : 'btn-outline-primary'">
{{title}}
</button>
<div class="dropdown-menu date-filter shadow pt-0" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
<div class="dropdown-menu date-dropdown shadow pt-0" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
<div class="list-group list-group-flush">
<button *ngFor="let qf of quickFilters" class="list-group-item small list-goup list-group-item-action d-flex p-2 pl-3" role="menuitem" (click)="setDateQuickFilter(qf.id)">
{{qf.name}}

View File

@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FilterDropodownComponent } from './filter-dropdown.component';
import { DateDropdownComponent } from './date-dropdown.component';
describe('FilterDropodownComponent', () => {
let component: FilterDropodownComponent;
let fixture: ComponentFixture<FilterDropodownComponent>;
describe('DateDropdownComponent', () => {
let component: DateDropdownComponent;
let fixture: ComponentFixture<DateDropdownComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FilterDropodownComponent ]
declarations: [ DateDropdownComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FilterDropodownComponent);
fixture = TestBed.createComponent(DateDropdownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@ -8,23 +8,23 @@ export interface DateSelection {
after?: string
}
const FILTER_LAST_7_DAYS = 0
const FILTER_LAST_MONTH = 1
const FILTER_LAST_3_MONTHS = 2
const FILTER_LAST_YEAR = 3
const LAST_7_DAYS = 0
const LAST_MONTH = 1
const LAST_3_MONTHS = 2
const LAST_YEAR = 3
@Component({
selector: 'app-filter-dropdown-date',
templateUrl: './filter-dropdown-date.component.html',
styleUrls: ['./filter-dropdown-date.component.scss']
selector: 'app-date-dropdown',
templateUrl: './date-dropdown.component.html',
styleUrls: ['./date-dropdown.component.scss']
})
export class FilterDropdownDateComponent implements OnInit, OnDestroy {
export class DateDropdownComponent implements OnInit, OnDestroy {
quickFilters = [
{id: FILTER_LAST_7_DAYS, name: "Last 7 days"},
{id: FILTER_LAST_MONTH, name: "Last month"},
{id: FILTER_LAST_3_MONTHS, name: "Last 3 months"},
{id: FILTER_LAST_YEAR, name: "Last year"}
{id: LAST_7_DAYS, name: "Last 7 days"},
{id: LAST_MONTH, name: "Last month"},
{id: LAST_3_MONTHS, name: "Last 3 months"},
{id: LAST_YEAR, name: "Last year"}
]
@Input()
@ -42,7 +42,7 @@ export class FilterDropdownDateComponent implements OnInit, OnDestroy {
private datesSetDebounce$ = new Subject()
private sub: Subscription
ngOnInit() {
this.sub = this.datesSetDebounce$.pipe(
debounceTime(400)
@ -61,22 +61,22 @@ export class FilterDropdownDateComponent implements OnInit, OnDestroy {
this.dateBefore = null
let date = new Date()
switch (qf) {
case FILTER_LAST_7_DAYS:
case LAST_7_DAYS:
date.setDate(date.getDate() - 7)
break;
case FILTER_LAST_MONTH:
case LAST_MONTH:
date.setMonth(date.getMonth() - 1)
break;
case FILTER_LAST_3_MONTHS:
case LAST_3_MONTHS:
date.setMonth(date.getMonth() - 3)
break
case FILTER_LAST_YEAR:
case LAST_YEAR:
date.setFullYear(date.getFullYear() - 1)
break
}
this.dateAfter = formatDate(date, 'yyyy-MM-dd', "en-us", "UTC")
this.onChange()

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FilterableDropodownButtonComponent } from './filterable-dropdown-button.component';
describe('FilterableDropodownButtonComponent', () => {
let component: FilterableDropodownButtonComponent;
let fixture: ComponentFixture<FilterableDropodownButtonComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FilterableDropodownButtonComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FilterableDropodownButtonComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -4,11 +4,11 @@ import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
@Component({
selector: 'app-filter-dropdown-button',
templateUrl: './filter-dropdown-button.component.html',
styleUrls: ['./filter-dropdown-button.component.scss']
selector: 'app-filterable-dropdown-button',
templateUrl: './filterable-dropdown-button.component.html',
styleUrls: ['./filterable-dropdown-button.component.scss']
})
export class FilterDropdownButtonComponent implements OnInit {
export class FilterableDropdownButtonComponent implements OnInit {
@Input()
item: PaperlessTag | PaperlessDocumentType | PaperlessCorrespondent

View File

@ -1,4 +1,4 @@
<div class="btn-group" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #filterDropdown="ngbDropdown">
<div class="btn-group" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #dropdown="ngbDropdown">
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="itemsSelected?.length > 0 ? 'btn-primary' : 'btn-outline-primary'">
<div class="d-none d-md-inline">{{title}}</div>
<div class="d-inline-block d-md-none">
@ -21,7 +21,7 @@
</div>
<div *ngIf="items" class="items">
<ng-container *ngFor="let item of items | filter: filterText; let i = index">
<app-filter-dropdown-button [item]="item" [selected]="isItemSelected(item)" (toggle)="toggleItem($event)"></app-filter-dropdown-button>
<app-filterable-dropdown-button [item]="item" [selected]="isItemSelected(item)" (toggle)="toggleItem($event)"></app-filterable-dropdown-button>
</ng-container>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FilterableDropodownComponent } from './filterable-dropdown.component';
describe('FilterableDropodownComponent', () => {
let component: FilterableDropodownComponent;
let fixture: ComponentFixture<FilterableDropodownComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FilterableDropodownComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FilterableDropodownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -4,11 +4,11 @@ import { FilterPipe } from 'src/app/pipes/filter.pipe';
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
@Component({
selector: 'app-filter-dropdown',
templateUrl: './filter-dropdown.component.html',
styleUrls: ['./filter-dropdown.component.scss']
selector: 'app-filterable-dropdown',
templateUrl: './filterable-dropdown.component.html',
styleUrls: ['./filterable-dropdown.component.scss']
})
export class FilterDropdownComponent {
export class FilterableDropdownComponent {
constructor(private filterPipe: FilterPipe) { }
@ -28,7 +28,7 @@ export class FilterDropdownComponent {
toggle = new EventEmitter()
@ViewChild('listFilterTextInput') listFilterTextInput: ElementRef
@ViewChild('filterDropdown') filterDropdown: NgbDropdown
@ViewChild('dropdown') dropdown: NgbDropdown
filterText: string
@ -53,6 +53,6 @@ export class FilterDropdownComponent {
listFilterEnter(): void {
let filtered = this.filterPipe.transform(this.items, this.filterText)
if (filtered.length == 1) this.toggleItem(filtered.shift())
this.filterDropdown.close()
this.dropdown.close()
}
}

View File

@ -11,7 +11,7 @@ import { DocumentService, DOCUMENT_SORT_FIELDS } from 'src/app/services/rest/doc
import { TagService } from 'src/app/services/rest/tag.service';
import { SavedViewService } from 'src/app/services/rest/saved-view.service';
import { Toast, ToastService } from 'src/app/services/toast.service';
import { FilterEditorComponent } from '../filter-editor/filter-editor.component';
import { FilterEditorComponent } from './filter-editor/filter-editor.component';
import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component';
import { SelectDialogComponent } from '../common/select-dialog/select-dialog.component';
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component';

View File

@ -8,11 +8,11 @@
<div class="w-100 d-xl-none"></div>
<div class="col col-xl-auto mb-2 mb-xl-0">
<div class="d-flex">
<app-filter-dropdown class="mr-2 mr-md-3" [items]="tags" [itemsSelected]="selectedTags" title="Tags" icon="tag-fill" (toggle)="toggleTag($event.id)"></app-filter-dropdown>
<app-filter-dropdown class="mr-2 mr-md-3" [items]="correspondents" [itemsSelected]="selectedCorrespondents" title="Correspondents" icon="person-fill" (toggle)="toggleCorrespondent($event.id)"></app-filter-dropdown>
<app-filter-dropdown class="mr-2 mr-md-3" [items]="documentTypes" [itemsSelected]="selectedDocumentTypes" title="Document types" icon="file-earmark-fill" (toggle)="toggleDocumentType($event.id)"></app-filter-dropdown>
<app-filter-dropdown-date class="mr-2 mr-md-3" [dateBefore]="dateCreatedBefore" [dateAfter]="dateCreatedAfter" title="Created" (datesSet)="onDatesCreatedSet($event)"></app-filter-dropdown-date>
<app-filter-dropdown-date [dateBefore]="dateAddedBefore" [dateAfter]="dateAddedAfter" title="Added" (datesSet)="onDatesAddedSet($event)"></app-filter-dropdown-date>
<app-filterable-dropdown class="mr-2 mr-md-3" [items]="tags" [itemsSelected]="selectedTags" title="Tags" icon="tag-fill" (toggle)="toggleTag($event.id)"></app-filterable-dropdown>
<app-filterable-dropdown class="mr-2 mr-md-3" [items]="correspondents" [itemsSelected]="selectedCorrespondents" title="Correspondents" icon="person-fill" (toggle)="toggleCorrespondent($event.id)"></app-filterable-dropdown>
<app-filterable-dropdown class="mr-2 mr-md-3" [items]="documentTypes" [itemsSelected]="selectedDocumentTypes" title="Document types" icon="file-earmark-fill" (toggle)="toggleDocumentType($event.id)"></app-filterable-dropdown>
<app-date-dropdown class="mr-2 mr-md-3" [dateBefore]="dateCreatedBefore" [dateAfter]="dateCreatedAfter" title="Created" (datesSet)="onDatesCreatedSet($event)"></app-date-dropdown>
<app-date-dropdown [dateBefore]="dateAddedBefore" [dateAfter]="dateAddedAfter" title="Added" (datesSet)="onDatesAddedSet($event)"></app-date-dropdown>
</div>
</div>
<div class="w-100 d-xl-none"></div>

View File

@ -10,7 +10,7 @@ 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 { DateSelection } from './filter-dropdown-date/filter-dropdown-date.component';
import { DateSelection } from 'src/app/components/common/date-dropdown/date-dropdown.component';
@Component({
selector: 'app-filter-editor',
@ -23,7 +23,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
if (this.filterRules.length == 1) {
let rule = this.filterRules[0]
switch(this.filterRules[0].rule_type) {
case FILTER_CORRESPONDENT:
return `Correspondent: ${this.correspondents.find(c => c.id == +rule.value)?.name}`
@ -55,7 +55,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
@Output()
filterRulesChange = new EventEmitter<FilterRule[]>()
hasFilters() {
return this.filterRules.length > 0
}
@ -123,7 +123,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
let existingRule = this.filterRules.find(rule => rule.rule_type == filterRuleTypeID && rule.value == value?.toString())
let existingRuleOfSameType = this.filterRules.find(rule => rule.rule_type == filterRuleTypeID)
if (existingRule) {
// if this exact rule already exists, remove it in all cases.
this.filterRules.splice(this.filterRules.indexOf(existingRule), 1)

View File

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FilterDropdownDateComponent } from './filter-dropdown-date.component';
describe('FilterDropdownDateComponent', () => {
let component: FilterDropdownDateComponent;
let fixture: ComponentFixture<FilterDropdownDateComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FilterDropdownDateComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FilterDropdownDateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FilterDropodownButtonComponent } from './filter-dropdown-button.component';
describe('FilterDropodownButtonComponent', () => {
let component: FilterDropodownButtonComponent;
let fixture: ComponentFixture<FilterDropodownButtonComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FilterDropodownButtonComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FilterDropodownButtonComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});