mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
parent
b262ec4b32
commit
dfb88ebf83
@ -4,38 +4,39 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu date-filter shadow pt-0" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
|
<div class="dropdown-menu date-filter shadow pt-0" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<button class="list-group-item small list-goup list-group-item-action d-flex p-2 pl-3" (click)="clear()">Clear</button>
|
<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)">
|
||||||
<button *ngFor="let range of [7, 30, 'month', 'year']" class="list-group-item small list-goup list-group-item-action d-flex p-2 pl-3" role="menuitem" (click)="setDateQuickFilter(range)">
|
{{qf.name}}
|
||||||
<ng-container *ngIf="isStringRange(range)">This </ng-container>
|
|
||||||
{{ range }}
|
|
||||||
<ng-container *ngIf="!isStringRange(range)"> days</ng-container>
|
|
||||||
</button>
|
</button>
|
||||||
<div class="list-group-item d-flex flex-column align-items-start" role="menuitem">
|
<div class="list-group-item d-flex flex-column align-items-start" role="menuitem">
|
||||||
<div>Before</div>
|
|
||||||
|
<div class="mb-2 d-flex flex-row w-100 justify-content-between small">
|
||||||
|
<div>After</div>
|
||||||
|
<a *ngIf="dateAfter" class="btn btn-link p-0 m-0" (click)="clearAfter()">
|
||||||
|
<svg width="0.8em" height="0.8em" viewBox="0 0 16 16" class="bi bi-x" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" />
|
||||||
|
</svg>
|
||||||
|
<small>Clear</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<input class="form-control" type="text" placeholder="yyyy-mm-dd" name="before" [(ngModel)]="_dateBefore" [maxDate]="this._maxDate" ngbDatepicker (dateSelect)="onBeforeSelected($event)" #dpBefore="ngbDatepicker">
|
<input type="date" class="form-control" id="date_after" [(ngModel)]="dateAfter" (change)="onChangeDebounce()">
|
||||||
<div class="input-group-append">
|
|
||||||
<button class="btn btn-outline-secondary btn-sm" (click)="dpBefore.toggle()" type="button">
|
|
||||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-calendar-date" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill-rule="evenodd" d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
|
|
||||||
<path d="M6.445 11.688V6.354h-.633A12.6 12.6 0 0 0 4.5 7.16v.695c.375-.257.969-.62 1.258-.777h.012v4.61h.675zm1.188-1.305c.047.64.594 1.406 1.703 1.406 1.258 0 2-1.066 2-2.871 0-1.934-.781-2.668-1.953-2.668-.926 0-1.797.672-1.797 1.809 0 1.16.824 1.77 1.676 1.77.746 0 1.23-.376 1.383-.79h.027c-.004 1.316-.461 2.164-1.305 2.164-.664 0-1.008-.45-1.05-.82h-.684zm2.953-2.317c0 .696-.559 1.18-1.184 1.18-.601 0-1.144-.383-1.144-1.2 0-.823.582-1.21 1.168-1.21.633 0 1.16.398 1.16 1.23z"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group-item d-flex flex-column align-items-start" role="menuitem">
|
<div class="list-group-item d-flex flex-column align-items-start" role="menuitem">
|
||||||
<div>After</div>
|
|
||||||
|
<div class="mb-2 d-flex flex-row w-100 justify-content-between small">
|
||||||
|
<div>Before</div>
|
||||||
|
<a *ngIf="dateBefore" class="btn btn-link p-0 m-0" (click)="clearBefore()">
|
||||||
|
<svg width="0.8em" height="0.8em" viewBox="0 0 16 16" class="bi bi-x" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" />
|
||||||
|
</svg>
|
||||||
|
<small>Clear</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<input class="form-control form-control-sm" type="text" placeholder="yyyy-mm-dd" name="after" [(ngModel)]="_dateAfter" [maxDate]="this._maxDate" ngbDatepicker (dateSelect)="onAfterSelected($event)" #dpAfter="ngbDatepicker">
|
<input type="date" class="form-control" id="date_before" [(ngModel)]="dateBefore" (change)="onChangeDebounce()">
|
||||||
<div class="input-group-append">
|
|
||||||
<button class="btn btn-outline-secondary btn-sm" (click)="dpAfter.toggle()" type="button">
|
|
||||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-calendar-date" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill-rule="evenodd" d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
|
|
||||||
<path d="M6.445 11.688V6.354h-.633A12.6 12.6 0 0 0 4.5 7.16v.695c.375-.257.969-.62 1.258-.777h.012v4.61h.675zm1.188-1.305c.047.64.594 1.406 1.703 1.406 1.258 0 2-1.066 2-2.871 0-1.934-.781-2.668-1.953-2.668-.926 0-1.797.672-1.797 1.809 0 1.16.824 1.77 1.676 1.77.746 0 1.23-.376 1.383-.79h.027c-.004 1.316-.461 2.164-1.305 2.164-.664 0-1.008-.45-1.05-.82h-.684zm2.953-2.317c0 .696-.559 1.18-1.184 1.18-.601 0-1.144-.383-1.144-1.2 0-.823.582-1.21 1.168-1.21.633 0 1.16.398 1.16 1.23z"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,24 +1,37 @@
|
|||||||
import { Component, EventEmitter, Input, Output, ElementRef, ViewChild, SimpleChange } from '@angular/core';
|
import { formatDate } from '@angular/common';
|
||||||
import { NgbDate, NgbDateStruct, NgbDatepicker } from '@ng-bootstrap/ng-bootstrap';
|
import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { Subject, Subscription } from 'rxjs';
|
||||||
|
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||||
|
|
||||||
export interface DateSelection {
|
export interface DateSelection {
|
||||||
before?: NgbDateStruct
|
before?: string
|
||||||
after?: NgbDateStruct
|
after?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FILTER_LAST_7_DAYS = 0
|
||||||
|
const FILTER_LAST_MONTH = 1
|
||||||
|
const FILTER_LAST_3_MONTHS = 2
|
||||||
|
const FILTER_LAST_YEAR = 3
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-filter-dropdown-date',
|
selector: 'app-filter-dropdown-date',
|
||||||
templateUrl: './filter-dropdown-date.component.html',
|
templateUrl: './filter-dropdown-date.component.html',
|
||||||
styleUrls: ['./filter-dropdown-date.component.scss']
|
styleUrls: ['./filter-dropdown-date.component.scss']
|
||||||
})
|
})
|
||||||
export class FilterDropdownDateComponent {
|
export class FilterDropdownDateComponent 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"}
|
||||||
|
]
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
dateBefore: NgbDateStruct
|
dateBefore: string
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
dateAfter: NgbDateStruct
|
dateAfter: string
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
title: string
|
title: string
|
||||||
@ -26,87 +39,65 @@ export class FilterDropdownDateComponent {
|
|||||||
@Output()
|
@Output()
|
||||||
datesSet = new EventEmitter<DateSelection>()
|
datesSet = new EventEmitter<DateSelection>()
|
||||||
|
|
||||||
@ViewChild('dpAfter') dpAfter: NgbDatepicker
|
private datesSetDebounce$ = new Subject()
|
||||||
@ViewChild('dpBefore') dpBefore: NgbDatepicker
|
|
||||||
|
|
||||||
_dateBefore: NgbDateStruct
|
private sub: Subscription
|
||||||
_dateAfter: NgbDateStruct
|
|
||||||
|
|
||||||
get _maxDate(): NgbDate {
|
ngOnInit() {
|
||||||
let date = new Date()
|
this.sub = this.datesSetDebounce$.pipe(
|
||||||
return NgbDate.from({year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate()})
|
debounceTime(400)
|
||||||
|
).subscribe(() => {
|
||||||
|
this.onChange()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
isStringRange(range: any) {
|
ngOnDestroy() {
|
||||||
return typeof range == 'string'
|
if (this.sub) {
|
||||||
}
|
this.sub.unsubscribe()
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChange) {
|
|
||||||
// this is a hacky workaround perhaps because of https://github.com/angular/angular/issues/11097
|
|
||||||
let dateString: string = ''
|
|
||||||
let dateAfterChange: SimpleChange
|
|
||||||
let dateBeforeChange: SimpleChange
|
|
||||||
if (changes) {
|
|
||||||
dateAfterChange = changes['dateAfter']
|
|
||||||
dateBeforeChange = changes['dateBefore']
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.dpBefore && this.dpAfter) {
|
setDateQuickFilter(qf: number) {
|
||||||
let dpAfterElRef: ElementRef = this.dpAfter['_elRef']
|
this.dateBefore = null
|
||||||
let dpBeforeElRef: ElementRef = this.dpBefore['_elRef']
|
let date = new Date()
|
||||||
|
switch (qf) {
|
||||||
|
case FILTER_LAST_7_DAYS:
|
||||||
|
date.setDate(date.getDate() - 7)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILTER_LAST_MONTH:
|
||||||
|
date.setMonth(date.getMonth() - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILTER_LAST_3_MONTHS:
|
||||||
|
date.setMonth(date.getMonth() - 3)
|
||||||
|
break
|
||||||
|
|
||||||
|
case FILTER_LAST_YEAR:
|
||||||
|
date.setFullYear(date.getFullYear() - 1)
|
||||||
|
break
|
||||||
|
|
||||||
if (dateAfterChange && dateAfterChange.currentValue) {
|
|
||||||
let dateAfterDate = dateAfterChange.currentValue as NgbDateStruct
|
|
||||||
dateString = `${dateAfterDate.year}-${dateAfterDate.month.toString().padStart(2,'0')}-${dateAfterDate.day.toString().padStart(2,'0')}`
|
|
||||||
dpAfterElRef.nativeElement.value = dateString
|
|
||||||
} else if (dateBeforeChange && dateBeforeChange.currentValue) {
|
|
||||||
let dateBeforeDate = dateBeforeChange.currentValue as NgbDateStruct
|
|
||||||
dateString = `${dateBeforeDate.year}-${dateBeforeDate.month.toString().padStart(2,'0')}-${dateBeforeDate.day.toString().padStart(2,'0')}`
|
|
||||||
dpBeforeElRef.nativeElement.value = dateString
|
|
||||||
} else {
|
|
||||||
dpAfterElRef.nativeElement.value = dateString
|
|
||||||
dpBeforeElRef.nativeElement.value = dateString
|
|
||||||
}
|
}
|
||||||
}
|
this.dateAfter = formatDate(date, 'yyyy-MM-dd', "en-us", "UTC")
|
||||||
|
this.onChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
setDateQuickFilter(range: any) {
|
onChange() {
|
||||||
let date = new Date()
|
this.datesSet.emit({after: this.dateAfter, before: this.dateBefore})
|
||||||
let newDate: NgbDateStruct = { year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate() }
|
|
||||||
switch (typeof range) {
|
|
||||||
case 'number':
|
|
||||||
date.setDate(date.getDate() - range)
|
|
||||||
newDate.year = date.getFullYear()
|
|
||||||
newDate.month = date.getMonth() + 1
|
|
||||||
newDate.day = date.getDate()
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'string':
|
|
||||||
newDate.day = 1
|
|
||||||
if (range == 'year') newDate.month = 1
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
this._dateAfter = newDate
|
|
||||||
this._dateBefore = null
|
|
||||||
this.datesSet.emit({after: newDate, before: null})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeSelected(date: NgbDateStruct) {
|
onChangeDebounce() {
|
||||||
this._dateBefore = date
|
this.datesSetDebounce$.next({after: this.dateAfter, before: this.dateBefore})
|
||||||
this.datesSet.emit({after: this._dateAfter, before: date})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onAfterSelected(date: NgbDateStruct) {
|
clearBefore() {
|
||||||
this._dateAfter = date
|
this.dateBefore = null;
|
||||||
this.datesSet.emit({after: date, before: this._dateBefore})
|
this.onChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clearAfter() {
|
||||||
this._dateBefore = null
|
this.dateAfter = null;
|
||||||
this._dateAfter = null
|
this.onChange()
|
||||||
this.datesSet.emit({after: null, before: null})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -179,54 +179,53 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
|||||||
this.applyFilters()
|
this.applyFilters()
|
||||||
}
|
}
|
||||||
|
|
||||||
get dateCreatedBefore(): NgbDateStruct {
|
get dateCreatedBefore(): string {
|
||||||
let createdBeforeRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_CREATED_BEFORE)
|
let createdBeforeRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_CREATED_BEFORE)
|
||||||
return createdBeforeRule ? this.dateParser.parse(createdBeforeRule.value) : null
|
return createdBeforeRule ? createdBeforeRule.value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
get dateCreatedAfter(): NgbDateStruct {
|
get dateCreatedAfter(): string {
|
||||||
let createdAfterRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_CREATED_AFTER)
|
let createdAfterRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_CREATED_AFTER)
|
||||||
return createdAfterRule ? this.dateParser.parse(createdAfterRule.value) : null
|
return createdAfterRule ? createdAfterRule.value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
get dateAddedBefore(): NgbDateStruct {
|
get dateAddedBefore(): string {
|
||||||
let addedBeforeRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_ADDED_BEFORE)
|
let addedBeforeRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_ADDED_BEFORE)
|
||||||
return addedBeforeRule ? this.dateParser.parse(addedBeforeRule.value) : null
|
return addedBeforeRule ? addedBeforeRule.value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
get dateAddedAfter(): NgbDateStruct {
|
get dateAddedAfter(): string {
|
||||||
let addedAfterRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_ADDED_AFTER)
|
let addedAfterRule: FilterRule = this.filterRules.find(fr => fr.rule_type == FILTER_ADDED_AFTER)
|
||||||
return addedAfterRule ? this.dateParser.parse(addedAfterRule.value) : null
|
return addedAfterRule ? addedAfterRule.value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
setDateCreatedBefore(date?: NgbDateStruct) {
|
setDateCreatedBefore(date?: string) {
|
||||||
if (date) this.setDateFilter(date, FILTER_CREATED_BEFORE)
|
if (date) this.setDateFilter(date, FILTER_CREATED_BEFORE)
|
||||||
else this.clearDateFilter(FILTER_CREATED_BEFORE)
|
else this.clearDateFilter(FILTER_CREATED_BEFORE)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDateCreatedAfter(date?: NgbDateStruct) {
|
setDateCreatedAfter(date?: string) {
|
||||||
if (date) this.setDateFilter(date, FILTER_CREATED_AFTER)
|
if (date) this.setDateFilter(date, FILTER_CREATED_AFTER)
|
||||||
else this.clearDateFilter(FILTER_CREATED_AFTER)
|
else this.clearDateFilter(FILTER_CREATED_AFTER)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDateAddedBefore(date?: NgbDateStruct) {
|
setDateAddedBefore(date?: string) {
|
||||||
if (date) this.setDateFilter(date, FILTER_ADDED_BEFORE)
|
if (date) this.setDateFilter(date, FILTER_ADDED_BEFORE)
|
||||||
else this.clearDateFilter(FILTER_ADDED_BEFORE)
|
else this.clearDateFilter(FILTER_ADDED_BEFORE)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDateAddedAfter(date?: NgbDateStruct) {
|
setDateAddedAfter(date?: string) {
|
||||||
if (date) this.setDateFilter(date, FILTER_ADDED_AFTER)
|
if (date) this.setDateFilter(date, FILTER_ADDED_AFTER)
|
||||||
else this.clearDateFilter(FILTER_ADDED_AFTER)
|
else this.clearDateFilter(FILTER_ADDED_AFTER)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDateFilter(date: NgbDateStruct, dateRuleTypeID: number) {
|
setDateFilter(date: string, dateRuleTypeID: number) {
|
||||||
let existingRule = this.filterRules.find(rule => rule.rule_type == dateRuleTypeID)
|
let existingRule = this.filterRules.find(rule => rule.rule_type == dateRuleTypeID)
|
||||||
let newValue = this.dateParser.format(date)
|
|
||||||
|
|
||||||
if (existingRule) {
|
if (existingRule) {
|
||||||
existingRule.value = newValue
|
existingRule.value = date
|
||||||
} else {
|
} else {
|
||||||
this.filterRules.push({rule_type: dateRuleTypeID, value: newValue})
|
this.filterRules.push({rule_type: dateRuleTypeID, value: date})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user