mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-22 15:57:51 +00:00
Ok do it on two lines, separate fields
This commit is contained in:
2 files changed
+95
-41
No files matched your search
+36
-30
@@ -33,36 +33,42 @@
|
||||
|
||||
<ng-template #comparisonValueTemplate let-atom="atom">
|
||||
@if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Date) {
|
||||
<div class="input-group input-group-sm w-100 order-1 mt-1">
|
||||
<select class="form-select w-auto flex-grow-0" aria-label="Date value type" i18n-aria-label
|
||||
[ngModel]="isRelativeDate(atom)" (ngModelChange)="setDateQueryMode(atom, $event)"
|
||||
[ngModelOptions]="{standalone: true}" [disabled]="disabled">
|
||||
<option [ngValue]="false" i18n>Fixed</option>
|
||||
<option [ngValue]="true" i18n>Relative</option>
|
||||
</select>
|
||||
@if (isRelativeDate(atom)) {
|
||||
<input class="form-control rounded-end" type="text" aria-label="Relative date" i18n-aria-label
|
||||
placeholder="e.g. in 30 days" i18n-placeholder
|
||||
[(ngModel)]="atom.value" [ngModelOptions]="{standalone: true}" [disabled]="disabled">
|
||||
} @else {
|
||||
<input class="form-control" placeholder="yyyy-mm-dd"
|
||||
[(ngModel)]="atom.value"
|
||||
[ngModelOptions]="{standalone: true}"
|
||||
[disabled]="disabled"
|
||||
ngbDatepicker
|
||||
#d="ngbDatepicker"
|
||||
[footerTemplate]="datePickerFooterTemplate" />
|
||||
<button class="btn btn-sm btn-outline-secondary rounded-end" (click)="d.toggle()" type="button" [disabled]="disabled" aria-label="Open date picker" i18n-aria-label>
|
||||
<i-bs name="calendar-event"></i-bs>
|
||||
</button>
|
||||
<ng-template #datePickerFooterTemplate>
|
||||
<div class="btn-group-xs border-top p-2 d-flex">
|
||||
<button type="button" class="btn btn-primary" (click)="atom.value = today; d.close()" i18n>Today</button>
|
||||
<button type="button" class="btn btn-secondary ms-auto" (click)="d.close()" i18n>Close</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
}
|
||||
</div>
|
||||
@let relativeDate = getRelativeDate(atom);
|
||||
<button class="btn btn-sm btn-outline-secondary" [class.active]="relativeDate" [class.rounded-end]="relativeDate" [attr.aria-pressed]="!!relativeDate" (click)="toggleRelativeDate(atom)" type="button" title="Relative date" i18n-title>
|
||||
<i-bs name="clock-history"></i-bs>
|
||||
</button>
|
||||
@if (relativeDate) {
|
||||
<div class="input-group input-group-sm w-100 order-1 mt-1">
|
||||
<input class="form-control w-25 flex-grow-0" type="number" min="0" aria-label="Amount" i18n-aria-label
|
||||
[ngModel]="relativeDate.amount"
|
||||
(ngModelChange)="updateRelativeDate(atom, { amount: $event })"
|
||||
[ngModelOptions]="{standalone: true}" />
|
||||
<select class="form-select" aria-label="Unit" i18n-aria-label
|
||||
[ngModel]="relativeDate.unit"
|
||||
(ngModelChange)="updateRelativeDate(atom, { unit: $event })"
|
||||
[ngModelOptions]="{standalone: true}">
|
||||
@for (unit of relativeDateUnits; track unit.id) {
|
||||
<option [ngValue]="unit.id">{{unit.label}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
} @else {
|
||||
<input class="form-control" placeholder="yyyy-mm-dd"
|
||||
[(ngModel)]="atom.value"
|
||||
[ngModelOptions]="{standalone: true}"
|
||||
ngbDatepicker
|
||||
#d="ngbDatepicker"
|
||||
[footerTemplate]="datePickerFooterTemplate" />
|
||||
<button class="btn btn-sm btn-outline-secondary rounded-end" (click)="d.toggle()" type="button" aria-label="Open date picker" i18n-aria-label>
|
||||
<i-bs name="calendar-event"></i-bs>
|
||||
</button>
|
||||
<ng-template #datePickerFooterTemplate>
|
||||
<div class="btn-group-xs border-top p-2 d-flex">
|
||||
<button type="button" class="btn btn-primary" (click)="atom.value = today; d.close()" i18n>Today</button>
|
||||
<button type="button" class="btn btn-secondary ms-auto" (click)="d.close()" i18n>Close</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
}
|
||||
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Float || getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Integer) {
|
||||
<input class="w-25 form-control rounded-end" type="number" [(ngModel)]="atom.value" [ngModelOptions]="{standalone: true}" [disabled]="disabled">
|
||||
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Boolean) {
|
||||
|
||||
+59
-11
@@ -49,6 +49,15 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
|
||||
import { ClearableBadgeComponent } from '../clearable-badge/clearable-badge.component'
|
||||
import { DocumentLinkComponent } from '../input/document-link/document-link.component'
|
||||
|
||||
// Matches the English expressions built by updateRelativeDate, e.g. "30 days ago" / "in 2 weeks"
|
||||
const RELATIVE_DATE_PATTERN =
|
||||
/^(?:(\d+) (days|weeks|months|years) ago|in (\d+) (days|weeks|months|years))$/
|
||||
|
||||
interface RelativeDate {
|
||||
amount: number | null
|
||||
unit: string
|
||||
}
|
||||
|
||||
export class CustomFieldQueriesModel {
|
||||
private readonly _queries = signal<CustomFieldQueryElement[]>([])
|
||||
private rootSubscriptions: Subscription[] = []
|
||||
@@ -305,20 +314,59 @@ export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPerm
|
||||
|
||||
public readonly today: string = new Date().toLocaleDateString('en-CA')
|
||||
|
||||
private readonly relativeDateModes = new Map<string, boolean>()
|
||||
public readonly relativeDateUnits = [
|
||||
{ id: 'days ago', label: $localize`days ago` },
|
||||
{ id: 'weeks ago', label: $localize`weeks ago` },
|
||||
{ id: 'months ago', label: $localize`months ago` },
|
||||
{ id: 'years ago', label: $localize`years ago` },
|
||||
{ id: 'days from now', label: $localize`days from now` },
|
||||
{ id: 'weeks from now', label: $localize`weeks from now` },
|
||||
{ id: 'months from now', label: $localize`months from now` },
|
||||
{ id: 'years from now', label: $localize`years from now` },
|
||||
]
|
||||
|
||||
isRelativeDate(atom: CustomFieldQueryAtom): boolean {
|
||||
return (
|
||||
this.relativeDateModes.get(atom.id) ??
|
||||
(typeof atom.value === 'string' &&
|
||||
!!atom.value &&
|
||||
!/^\d{4}-\d{2}-\d{2}$/.test(atom.value))
|
||||
)
|
||||
private readonly relativeDates = new Map<string, RelativeDate>()
|
||||
|
||||
getRelativeDate(atom: CustomFieldQueryAtom): RelativeDate | undefined {
|
||||
if (!this.relativeDates.has(atom.id)) {
|
||||
const match =
|
||||
typeof atom.value === 'string' &&
|
||||
atom.value.match(RELATIVE_DATE_PATTERN)
|
||||
if (match) {
|
||||
this.relativeDates.set(
|
||||
atom.id,
|
||||
match[1]
|
||||
? { amount: +match[1], unit: `${match[2]} ago` }
|
||||
: { amount: +match[3], unit: `${match[4]} from now` }
|
||||
)
|
||||
}
|
||||
}
|
||||
return this.relativeDates.get(atom.id)
|
||||
}
|
||||
|
||||
setDateQueryMode(atom: CustomFieldQueryAtom, relative: boolean) {
|
||||
this.relativeDateModes.set(atom.id, relative)
|
||||
atom.value = null
|
||||
toggleRelativeDate(atom: CustomFieldQueryAtom) {
|
||||
if (this.getRelativeDate(atom)) {
|
||||
this.relativeDates.delete(atom.id)
|
||||
atom.value = null
|
||||
} else {
|
||||
this.relativeDates.set(atom.id, { amount: null, unit: 'days ago' })
|
||||
this.updateRelativeDate(atom, {})
|
||||
}
|
||||
}
|
||||
|
||||
updateRelativeDate(
|
||||
atom: CustomFieldQueryAtom,
|
||||
change: Partial<RelativeDate>
|
||||
) {
|
||||
const relativeDate = Object.assign(this.relativeDates.get(atom.id), change)
|
||||
const { amount, unit } = relativeDate
|
||||
const [period, direction] = unit.split(' ', 2)
|
||||
atom.value =
|
||||
amount === null
|
||||
? null
|
||||
: direction === 'ago'
|
||||
? `${amount} ${unit}`
|
||||
: `in ${amount} ${period}`
|
||||
}
|
||||
|
||||
public customFieldSearchFn = (term: string, field: CustomField): boolean =>
|
||||
|
||||
Reference in new issue
Block a user