-
-
- @if (addedDateFrom) {
-
-
-
-
- }
+
+
+
+
+ @if (createdDateTo) {
+
+
+
+
+ }
+
+
-
-
-
-
- @if (addedDateTo) {
-
-
-
-
- }
+
+
+
+
+
+
+ @if (addedRelativeDate) {
+
+
+
+
+ }
+
+
+
+
+
+ @if (addedDateFrom) {
+
+
+
+
+ }
+
+
+
+
+ @if (addedDateTo) {
+
+
+
+
+ }
+
+
+
diff --git a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.scss b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.scss
index ebd34b29a..616835b3a 100644
--- a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.scss
+++ b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.scss
@@ -1,16 +1,7 @@
.date-dropdown {
+ --bs-dropdown-min-width: 22rem;
white-space: nowrap;
- @media(min-width: 768px) {
- --bs-dropdown-min-width: 40rem;
- }
-
- @media screen and (max-width: 767px) {
- .border-end {
- border: none !important;
- }
- }
-
.btn-link {
line-height: 1;
}
@@ -21,6 +12,10 @@
min-height: 1em;
}
+.select-item .selected-icon {
+ line-height: 2em;
+}
+
.input-group-sm {
.form-control {
font-size: 0.875rem;
diff --git a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.spec.ts b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.spec.ts
index 1f6ee909e..ee99a726b 100644
--- a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.spec.ts
+++ b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.spec.ts
@@ -82,10 +82,12 @@ describe('DatesDropdownComponent', () => {
it('should support relative dates', fakeAsync(() => {
let result: DateSelection
component.datesSet.subscribe((date) => (result = date))
- component.setCreatedRelativeDate(null)
- component.setCreatedRelativeDate(RelativeDate.WITHIN_1_WEEK)
- component.setAddedRelativeDate(null)
- component.setAddedRelativeDate(RelativeDate.WITHIN_1_WEEK)
+ component.createdRelativeDate = RelativeDate.WITHIN_1_WEEK // normally set by ngModel binding in dropdown
+ component.onSetCreatedRelativeDate({
+ id: RelativeDate.WITHIN_1_WEEK,
+ } as any)
+ component.addedRelativeDate = RelativeDate.WITHIN_1_WEEK // normally set by ngModel binding in dropdown
+ component.onSetAddedRelativeDate({ id: RelativeDate.WITHIN_1_WEEK } as any)
tick(500)
expect(result).toEqual({
createdFrom: null,
@@ -147,8 +149,19 @@ describe('DatesDropdownComponent', () => {
expect(component.addedDateTo).toBeNull()
})
+ it('should support clearRelativeDate', () => {
+ component.createdRelativeDate = RelativeDate.WITHIN_1_WEEK
+ component.clearCreatedRelativeDate()
+ expect(component.createdRelativeDate).toBeNull()
+
+ component.addedRelativeDate = RelativeDate.WITHIN_1_WEEK
+ component.clearAddedRelativeDate()
+ expect(component.addedRelativeDate).toBeNull()
+ })
+
it('should limit keyboard events', () => {
- const input: HTMLInputElement = fixture.nativeElement.querySelector('input')
+ const input: HTMLInputElement =
+ fixture.nativeElement.querySelector('input.form-control')
let event: KeyboardEvent = new KeyboardEvent('keypress', {
key: '9',
})
@@ -163,4 +176,19 @@ describe('DatesDropdownComponent', () => {
input.dispatchEvent(event)
expect(eventSpy).toHaveBeenCalled()
})
+
+ it('should support debounce', fakeAsync(() => {
+ let result: DateSelection
+ component.datesSet.subscribe((date) => (result = date))
+ component.onChangeDebounce()
+ tick(500)
+ expect(result).toEqual({
+ createdFrom: null,
+ createdTo: null,
+ createdRelativeDateID: null,
+ addedFrom: null,
+ addedTo: null,
+ addedRelativeDateID: null,
+ })
+ }))
})
diff --git a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts
index 50565aaa2..c220262a4 100644
--- a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts
+++ b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts
@@ -13,6 +13,7 @@ import {
NgbDatepickerModule,
NgbDropdownModule,
} from '@ng-bootstrap/ng-bootstrap'
+import { NgSelectModule } from '@ng-select/ng-select'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Subject, Subscription } from 'rxjs'
import { debounceTime } from 'rxjs/operators'
@@ -32,10 +33,14 @@ export interface DateSelection {
}
export enum RelativeDate {
- WITHIN_1_WEEK = 0,
- WITHIN_1_MONTH = 1,
- WITHIN_3_MONTHS = 2,
- WITHIN_1_YEAR = 3,
+ WITHIN_1_WEEK = 1,
+ WITHIN_1_MONTH = 2,
+ WITHIN_3_MONTHS = 3,
+ WITHIN_1_YEAR = 4,
+ THIS_YEAR = 5,
+ THIS_MONTH = 6,
+ TODAY = 7,
+ YESTERDAY = 8,
}
@Component({
@@ -49,6 +54,7 @@ export enum RelativeDate {
NgxBootstrapIconsModule,
NgbDatepickerModule,
NgbDropdownModule,
+ NgSelectModule,
FormsModule,
ReactiveFormsModule,
NgClass,
@@ -82,44 +88,64 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
name: $localize`Within 1 year`,
date: new Date().setFullYear(new Date().getFullYear() - 1),
},
+ {
+ id: RelativeDate.THIS_YEAR,
+ name: $localize`This year`,
+ date: new Date('1/1/' + new Date().getFullYear()),
+ },
+ {
+ id: RelativeDate.THIS_MONTH,
+ name: $localize`This month`,
+ date: new Date().setDate(1),
+ },
+ {
+ id: RelativeDate.TODAY,
+ name: $localize`Today`,
+ date: new Date().setHours(0, 0, 0, 0),
+ },
+ {
+ id: RelativeDate.YESTERDAY,
+ name: $localize`Yesterday`,
+ date: new Date().setDate(new Date().getDate() - 1),
+ },
]
datePlaceHolder: string
// created
@Input()
- createdDateTo: string
+ createdDateTo: string = null
@Output()
createdDateToChange = new EventEmitter
()
@Input()
- createdDateFrom: string
+ createdDateFrom: string = null
@Output()
createdDateFromChange = new EventEmitter()
@Input()
- createdRelativeDate: RelativeDate
+ createdRelativeDate: RelativeDate = null
@Output()
createdRelativeDateChange = new EventEmitter()
// added
@Input()
- addedDateTo: string
+ addedDateTo: string = null
@Output()
addedDateToChange = new EventEmitter()
@Input()
- addedDateFrom: string
+ addedDateFrom: string = null
@Output()
addedDateFromChange = new EventEmitter()
@Input()
- addedRelativeDate: RelativeDate
+ addedRelativeDate: RelativeDate = null
@Output()
addedRelativeDateChange = new EventEmitter()
@@ -133,6 +159,9 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
@Input()
disabled: boolean = false
+ @Input()
+ placement: string = 'bottom-start'
+
public readonly today: string = new Date().toISOString().split('T')[0]
get isActive(): boolean {
@@ -172,17 +201,17 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
this.onChange()
}
- setCreatedRelativeDate(rd: RelativeDate) {
+ onSetCreatedRelativeDate(rd: { id: number; name: string; date: number }) {
+ // createdRelativeDate is set by ngModel
this.createdDateTo = null
this.createdDateFrom = null
- this.createdRelativeDate = this.createdRelativeDate == rd ? null : rd
this.onChange()
}
- setAddedRelativeDate(rd: RelativeDate) {
+ onSetAddedRelativeDate(rd: { id: number; name: string; date: number }) {
+ // addedRelativeDate is set by ngModel
this.addedDateTo = null
this.addedDateFrom = null
- this.addedRelativeDate = this.addedRelativeDate == rd ? null : rd
this.onChange()
}
@@ -224,6 +253,11 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
this.onChange()
}
+ clearCreatedRelativeDate() {
+ this.createdRelativeDate = null
+ this.onChange()
+ }
+
clearAddedTo() {
this.addedDateTo = null
this.onChange()
@@ -234,6 +268,11 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
this.onChange()
}
+ clearAddedRelativeDate() {
+ this.addedRelativeDate = null
+ this.onChange()
+ }
+
// prevent chars other than numbers and separators
onKeyPress(event: KeyboardEvent) {
if ('Enter' !== event.key && !/[0-9,\.\/-]+/.test(event.key)) {
diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html
index fcb7bed8f..f8d346cba 100644
--- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html
+++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.html
@@ -93,6 +93,7 @@
}
{
value: 'created:[-1 week to now]',
},
]
- expect(component.dateCreatedRelativeDate).toEqual(0) // RELATIVE_DATE_QUERYSTRINGS['-1 week to now']
+ expect(component.dateCreatedRelativeDate).toEqual(1) // RELATIVE_DATE_QUERYSTRINGS['-1 week to now']
expect(component.textFilter).toBeNull()
}))
@@ -434,7 +437,7 @@ describe('FilterEditorComponent', () => {
value: 'added:[-1 week to now]',
},
]
- expect(component.dateAddedRelativeDate).toEqual(0) // RELATIVE_DATE_QUERYSTRINGS['-1 week to now']
+ expect(component.dateAddedRelativeDate).toEqual(1) // RELATIVE_DATE_QUERYSTRINGS['-1 week to now']
expect(component.textFilter).toBeNull()
}))
@@ -1587,10 +1590,8 @@ describe('FilterEditorComponent', () => {
const dateCreatedDropdown = fixture.debugElement.queryAll(
By.directive(DatesDropdownComponent)
)[0]
- const dateCreatedBeforeRelativeButton = dateCreatedDropdown.queryAll(
- By.css('button')
- )[1]
- dateCreatedBeforeRelativeButton.triggerEventHandler('click')
+ component.dateCreatedRelativeDate = RelativeDate.WITHIN_1_WEEK
+ dateCreatedDropdown.triggerEventHandler('datesSet')
fixture.detectChanges()
tick(400)
expect(component.filterRules).toEqual([
@@ -1606,10 +1607,8 @@ describe('FilterEditorComponent', () => {
const dateCreatedDropdown = fixture.debugElement.queryAll(
By.directive(DatesDropdownComponent)
)[0]
- const dateCreatedBeforeRelativeButton = dateCreatedDropdown.queryAll(
- By.css('button')
- )[1]
- dateCreatedBeforeRelativeButton.triggerEventHandler('click')
+ component.dateCreatedRelativeDate = RelativeDate.WITHIN_1_WEEK
+ dateCreatedDropdown.triggerEventHandler('datesSet')
fixture.detectChanges()
tick(400)
expect(component.filterRules).toEqual([
@@ -1692,16 +1691,14 @@ describe('FilterEditorComponent', () => {
const datesDropdown = fixture.debugElement.query(
By.directive(DatesDropdownComponent)
)
- const dateCreatedBeforeRelativeButton = datesDropdown.queryAll(
- By.css('button')
- )[1]
- dateCreatedBeforeRelativeButton.triggerEventHandler('click')
+ component.dateAddedRelativeDate = RelativeDate.WITHIN_1_WEEK
+ datesDropdown.triggerEventHandler('datesSet')
fixture.detectChanges()
tick(400)
expect(component.filterRules).toEqual([
{
rule_type: FILTER_FULLTEXT_QUERY,
- value: 'created:[-1 week to now]',
+ value: 'added:[-1 week to now]',
},
])
}))
@@ -1711,16 +1708,14 @@ describe('FilterEditorComponent', () => {
const datesDropdown = fixture.debugElement.query(
By.directive(DatesDropdownComponent)
)
- const dateCreatedBeforeRelativeButton = datesDropdown.queryAll(
- By.css('button')
- )[1]
- dateCreatedBeforeRelativeButton.triggerEventHandler('click')
+ component.dateAddedRelativeDate = RelativeDate.WITHIN_1_WEEK
+ datesDropdown.triggerEventHandler('datesSet')
fixture.detectChanges()
tick(400)
expect(component.filterRules).toEqual([
{
rule_type: FILTER_FULLTEXT_QUERY,
- value: 'foo,created:[-1 week to now]',
+ value: 'foo,added:[-1 week to now]',
},
])
}))
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 0916d9c0d..900e72785 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
@@ -135,24 +135,44 @@ const TEXT_FILTER_MODIFIER_NOTNULL = 'not null'
const TEXT_FILTER_MODIFIER_GT = 'greater'
const TEXT_FILTER_MODIFIER_LT = 'less'
-const RELATIVE_DATE_QUERY_REGEXP_CREATED = /created:\[([^\]]+)\]/g
-const RELATIVE_DATE_QUERY_REGEXP_ADDED = /added:\[([^\]]+)\]/g
+const RELATIVE_DATE_QUERY_REGEXP_CREATED = /created:[\["]([^\]]+)[\]"]/g
+const RELATIVE_DATE_QUERY_REGEXP_ADDED = /added:[\["]([^\]]+)[\]"]/g
const RELATIVE_DATE_QUERYSTRINGS = [
{
relativeDate: RelativeDate.WITHIN_1_WEEK,
dateQuery: '-1 week to now',
+ isRange: true,
},
{
relativeDate: RelativeDate.WITHIN_1_MONTH,
dateQuery: '-1 month to now',
+ isRange: true,
},
{
relativeDate: RelativeDate.WITHIN_3_MONTHS,
dateQuery: '-3 month to now',
+ isRange: true,
},
{
relativeDate: RelativeDate.WITHIN_1_YEAR,
dateQuery: '-1 year to now',
+ isRange: true,
+ },
+ {
+ relativeDate: RelativeDate.THIS_YEAR,
+ dateQuery: 'this year',
+ },
+ {
+ relativeDate: RelativeDate.THIS_MONTH,
+ dateQuery: 'this month',
+ },
+ {
+ relativeDate: RelativeDate.TODAY,
+ dateQuery: 'today',
+ },
+ {
+ relativeDate: RelativeDate.YESTERDAY,
+ dateQuery: 'yesterday',
},
]
@@ -907,12 +927,11 @@ export class FilterEditorComponent
let existingRuleArgs = existingRule?.value.split(',')
if (this.dateCreatedRelativeDate !== null) {
+ const rd = RELATIVE_DATE_QUERYSTRINGS.find(
+ (qS) => qS.relativeDate == this.dateCreatedRelativeDate
+ )
queryArgs.push(
- `created:[${
- RELATIVE_DATE_QUERYSTRINGS.find(
- (qS) => qS.relativeDate == this.dateCreatedRelativeDate
- ).dateQuery
- }]`
+ `created:${rd.isRange ? `[${rd.dateQuery}]` : `"${rd.dateQuery}"`}`
)
if (existingRule) {
queryArgs = existingRuleArgs
@@ -921,12 +940,11 @@ export class FilterEditorComponent
}
}
if (this.dateAddedRelativeDate !== null) {
+ const rd = RELATIVE_DATE_QUERYSTRINGS.find(
+ (qS) => qS.relativeDate == this.dateAddedRelativeDate
+ )
queryArgs.push(
- `added:[${
- RELATIVE_DATE_QUERYSTRINGS.find(
- (qS) => qS.relativeDate == this.dateAddedRelativeDate
- ).dateQuery
- }]`
+ `added:${rd.isRange ? `[${rd.dateQuery}]` : `"${rd.dateQuery}"`}`
)
if (existingRule) {
queryArgs = existingRuleArgs