Enhancement: date picker and date filter dropdown improvements (#9033)

This commit is contained in:
shamoon 2025-02-06 23:01:48 -08:00 committed by GitHub
parent 52ab07c673
commit e08606af6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 561 additions and 254 deletions

View File

@ -83,9 +83,9 @@ test('date filtering', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' }) await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' })
await page.goto('/documents') await page.goto('/documents')
await page.getByRole('button', { name: 'Dates' }).click() await page.getByRole('button', { name: 'Dates' }).click()
await page.getByRole('menuitem', { name: 'Last 3 months' }).first().click() await page.getByRole('menuitem', { name: 'Within 3 months' }).first().click()
await expect(page.locator('pngx-document-list')).toHaveText(/one document/i) await expect(page.locator('pngx-document-list')).toHaveText(/one document/i)
await page.getByRole('menuitem', { name: 'Last 3 months' }).first().click() await page.getByRole('menuitem', { name: 'Within 3 months' }).first().click()
await page.getByLabel('Datesselected').getByRole('button').first().click() await page.getByLabel('Datesselected').getByRole('button').first().click()
await page.getByRole('combobox', { name: 'Select month' }).selectOption('12') await page.getByRole('combobox', { name: 'Select month' }).selectOption('12')
await page.getByRole('combobox', { name: 'Select year' }).selectOption('2022') await page.getByRole('combobox', { name: 'Select year' }).selectOption('2022')

View File

@ -3687,7 +3687,7 @@
"time": 1.501, "time": 1.501,
"request": { "request": {
"method": "GET", "method": "GET",
"url": "http://localhost:8000/api/documents/?page=1&page_size=50&ordering=-created&truncate_content=true&created__date__gt=2022-12-11", "url": "http://localhost:8000/api/documents/?page=1&page_size=50&ordering=-created&truncate_content=true&created__date__gte=2022-12-11",
"httpVersion": "HTTP/1.1", "httpVersion": "HTTP/1.1",
"cookies": [], "cookies": [],
"headers": [ "headers": [
@ -3721,7 +3721,7 @@
"value": "true" "value": "true"
}, },
{ {
"name": "created__date__gt", "name": "created__date__gte",
"value": "2022-12-11" "value": "2022-12-11"
} }
], ],

View File

@ -1167,7 +1167,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">166</context> <context context-type="linenumber">170</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7314814725704332646" datatype="html"> <trans-unit id="7314814725704332646" datatype="html">
@ -3318,48 +3318,114 @@
<context context-type="linenumber">93</context> <context context-type="linenumber">93</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4465085913683915434" datatype="html"> <trans-unit id="6048892649018070225" datatype="html">
<source>True</source> <source>Today</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">39</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">50</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">76</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">126</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">152</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context>
<context context-type="linenumber">21</context>
</context-group>
</trans-unit>
<trans-unit id="7819314041543176992" datatype="html">
<source>Close</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">40</context> <context context-type="linenumber">40</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">51</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">77</context> <context context-type="linenumber">77</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">127</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">153</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context>
<context context-type="linenumber">22</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">94</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1375</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">37</context>
</context-group>
</trans-unit>
<trans-unit id="4465085913683915434" datatype="html">
<source>True</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">83</context> <context context-type="linenumber">47</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">90</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3800326155195149498" datatype="html"> <trans-unit id="3800326155195149498" datatype="html">
<source>False</source> <source>False</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">41</context> <context context-type="linenumber">48</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">78</context> <context context-type="linenumber">85</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">84</context> <context context-type="linenumber">91</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7551700625201096185" datatype="html"> <trans-unit id="7551700625201096185" datatype="html">
<source>Search docs...</source> <source>Search docs...</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">100</context> <context context-type="linenumber">107</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3184700926171002527" datatype="html"> <trans-unit id="3184700926171002527" datatype="html">
<source>Any</source> <source>Any</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">132</context> <context context-type="linenumber">139</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
@ -3370,7 +3436,7 @@
<source>All</source> <source>All</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">134</context> <context context-type="linenumber">141</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
@ -3397,21 +3463,21 @@
<source>Not</source> <source>Not</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">137</context> <context context-type="linenumber">144</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6548676277933116532" datatype="html"> <trans-unit id="6548676277933116532" datatype="html">
<source>Add query</source> <source>Add query</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">156</context> <context context-type="linenumber">163</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5599577087865387184" datatype="html"> <trans-unit id="5599577087865387184" datatype="html">
<source>Add expression</source> <source>Add expression</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
<context context-type="linenumber">159</context> <context context-type="linenumber">166</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6052766076365105714" datatype="html"> <trans-unit id="6052766076365105714" datatype="html">
@ -3422,36 +3488,36 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">89</context> <context context-type="linenumber">101</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6371576811194810854" datatype="html"> <trans-unit id="5203279511751768967" datatype="html">
<source>After</source> <source>From</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">42</context> <context context-type="linenumber">42</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">106</context> <context context-type="linenumber">118</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1218334388194408974" datatype="html"> <trans-unit id="1640609344969975994" datatype="html">
<source>Before</source> <source>To</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">62</context> <context context-type="linenumber">68</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">126</context> <context context-type="linenumber">144</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="231679111972850796" datatype="html"> <trans-unit id="231679111972850796" datatype="html">
<source>Added</source> <source>Added</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.html</context>
<context context-type="linenumber">74</context> <context context-type="linenumber">86</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context> <context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
@ -3470,41 +3536,33 @@
<context context-type="linenumber">93</context> <context context-type="linenumber">93</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4873149362496451858" datatype="html"> <trans-unit id="9129856334122659953" datatype="html">
<source>Last 7 days</source> <source>Within 1 week</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">67</context> <context context-type="linenumber">67</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4463380307954693363" datatype="html"> <trans-unit id="123064370501514576" datatype="html">
<source>Last month</source> <source>Within 1 month</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">72</context> <context context-type="linenumber">72</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pipes/custom-date.pipe.ts</context>
<context context-type="linenumber">19</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8697368973702409683" datatype="html"> <trans-unit id="1027161426440526546" datatype="html">
<source>Last 3 months</source> <source>Within 3 months</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">77</context> <context context-type="linenumber">77</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3566342898065860218" datatype="html"> <trans-unit id="226779700214642230" datatype="html">
<source>Last year</source> <source>Within 1 year</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context> <context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">82</context> <context context-type="linenumber">82</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pipes/custom-date.pipe.ts</context>
<context context-type="linenumber">14</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8743659855412792665" datatype="html"> <trans-unit id="8743659855412792665" datatype="html">
<source>Matching algorithm</source> <source>Matching algorithm</source>
@ -5071,14 +5129,14 @@
<source>Invalid date.</source> <source>Invalid date.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context> <context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context>
<context context-type="linenumber">25</context> <context context-type="linenumber">31</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="524422427194414813" datatype="html"> <trans-unit id="524422427194414813" datatype="html">
<source>Suggestions:</source> <source>Suggestions:</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context> <context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context>
<context context-type="linenumber">31</context> <context context-type="linenumber">37</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/select/select.component.html</context> <context context-type="sourcefile">src/app/components/common/input/select/select.component.html</context>
@ -5093,7 +5151,7 @@
<source>Filter documents with this <x id="PH" equiv-text="this.title"/></source> <source>Filter documents with this <x id="PH" equiv-text="this.title"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/date/date.component.ts</context> <context context-type="sourcefile">src/app/components/common/input/date/date.component.ts</context>
<context context-type="linenumber">121</context> <context context-type="linenumber">123</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/input/select/select.component.ts</context> <context context-type="sourcefile">src/app/components/common/input/select/select.component.ts</context>
@ -6257,21 +6315,6 @@
<context context-type="linenumber">70</context> <context context-type="linenumber">70</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7819314041543176992" datatype="html">
<source>Close</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">94</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1375</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">37</context>
</context-group>
</trans-unit>
<trans-unit id="4452427314943113135" datatype="html"> <trans-unit id="4452427314943113135" datatype="html">
<source>Previous</source> <source>Previous</source>
<context-group purpose="location"> <context-group purpose="location">
@ -6298,7 +6341,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">154</context> <context context-type="linenumber">158</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/document.ts</context> <context context-type="sourcefile">src/app/data/document.ts</context>
@ -6926,7 +6969,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">162</context> <context context-type="linenumber">166</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6475890479659129881" datatype="html"> <trans-unit id="6475890479659129881" datatype="html">
@ -7528,7 +7571,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">159</context> <context context-type="linenumber">163</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/document.ts</context> <context context-type="sourcefile">src/app/data/document.ts</context>
@ -7717,147 +7760,147 @@
<source>Title &amp; content</source> <source>Title &amp; content</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">157</context> <context context-type="linenumber">161</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2649431021108393503" datatype="html"> <trans-unit id="2649431021108393503" datatype="html">
<source>More like</source> <source>More like</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">172</context> <context context-type="linenumber">176</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3697582909018473071" datatype="html"> <trans-unit id="3697582909018473071" datatype="html">
<source>equals</source> <source>equals</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">178</context> <context context-type="linenumber">182</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5325481293405718739" datatype="html"> <trans-unit id="5325481293405718739" datatype="html">
<source>is empty</source> <source>is empty</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">182</context> <context context-type="linenumber">186</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6166785695326182482" datatype="html"> <trans-unit id="6166785695326182482" datatype="html">
<source>is not empty</source> <source>is not empty</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">186</context> <context context-type="linenumber">190</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4686622206659266699" datatype="html"> <trans-unit id="4686622206659266699" datatype="html">
<source>greater than</source> <source>greater than</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">190</context> <context context-type="linenumber">194</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8014012170270529279" datatype="html"> <trans-unit id="8014012170270529279" datatype="html">
<source>less than</source> <source>less than</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">194</context> <context context-type="linenumber">198</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5195932016807797291" datatype="html"> <trans-unit id="5195932016807797291" datatype="html">
<source>Correspondent: <x id="PH" equiv-text="this.correspondents.find((c) =&gt; c.id == +rule.value)?.name"/></source> <source>Correspondent: <x id="PH" equiv-text="this.correspondents.find((c) =&gt; c.id == +rule.value)?.name"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">226,228</context> <context context-type="linenumber">230,232</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8170755470576301659" datatype="html"> <trans-unit id="8170755470576301659" datatype="html">
<source>Without correspondent</source> <source>Without correspondent</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">230</context> <context context-type="linenumber">234</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="317796810569008208" datatype="html"> <trans-unit id="317796810569008208" datatype="html">
<source>Document type: <x id="PH" equiv-text="this.documentTypes.find((dt) =&gt; dt.id == +rule.value)?.name"/></source> <source>Document type: <x id="PH" equiv-text="this.documentTypes.find((dt) =&gt; dt.id == +rule.value)?.name"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">236,238</context> <context context-type="linenumber">240,242</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4362173610367509215" datatype="html"> <trans-unit id="4362173610367509215" datatype="html">
<source>Without document type</source> <source>Without document type</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">240</context> <context context-type="linenumber">244</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="232202047340644471" datatype="html"> <trans-unit id="232202047340644471" datatype="html">
<source>Storage path: <x id="PH" equiv-text="this.storagePaths.find((sp) =&gt; sp.id == +rule.value)?.name"/></source> <source>Storage path: <x id="PH" equiv-text="this.storagePaths.find((sp) =&gt; sp.id == +rule.value)?.name"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">246,248</context> <context context-type="linenumber">250,252</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1562820715074533164" datatype="html"> <trans-unit id="1562820715074533164" datatype="html">
<source>Without storage path</source> <source>Without storage path</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">250</context> <context context-type="linenumber">254</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8180755793012580465" datatype="html"> <trans-unit id="8180755793012580465" datatype="html">
<source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)?.name"/></source> <source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)?.name"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">254,256</context> <context context-type="linenumber">258,260</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6494566478302448576" datatype="html"> <trans-unit id="6494566478302448576" datatype="html">
<source>Without any tag</source> <source>Without any tag</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">260</context> <context context-type="linenumber">264</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8644099678903817943" datatype="html"> <trans-unit id="8644099678903817943" datatype="html">
<source>Custom fields query</source> <source>Custom fields query</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">264</context> <context context-type="linenumber">268</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6523384805359286307" datatype="html"> <trans-unit id="6523384805359286307" datatype="html">
<source>Title: <x id="PH" equiv-text="rule.value"/></source> <source>Title: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">267</context> <context context-type="linenumber">271</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1872523635812236432" datatype="html"> <trans-unit id="1872523635812236432" datatype="html">
<source>ASN: <x id="PH" equiv-text="rule.value"/></source> <source>ASN: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">270</context> <context context-type="linenumber">274</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="102674688969746976" datatype="html"> <trans-unit id="102674688969746976" datatype="html">
<source>Owner: <x id="PH" equiv-text="rule.value"/></source> <source>Owner: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">273</context> <context context-type="linenumber">277</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3550877650686009106" datatype="html"> <trans-unit id="3550877650686009106" datatype="html">
<source>Owner not in: <x id="PH" equiv-text="rule.value"/></source> <source>Owner not in: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">276</context> <context context-type="linenumber">280</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1082034558646673343" datatype="html"> <trans-unit id="1082034558646673343" datatype="html">
<source>Without an owner</source> <source>Without an owner</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">279</context> <context context-type="linenumber">283</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7210076240260527720" datatype="html"> <trans-unit id="7210076240260527720" datatype="html">
@ -9149,6 +9192,13 @@
<context context-type="linenumber">36</context> <context context-type="linenumber">36</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3566342898065860218" datatype="html">
<source>Last year</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pipes/custom-date.pipe.ts</context>
<context context-type="linenumber">14</context>
</context-group>
</trans-unit>
<trans-unit id="3393387677918927062" datatype="html"> <trans-unit id="3393387677918927062" datatype="html">
<source>%s years ago</source> <source>%s years ago</source>
<context-group purpose="location"> <context-group purpose="location">
@ -9156,6 +9206,13 @@
<context context-type="linenumber">15</context> <context context-type="linenumber">15</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4463380307954693363" datatype="html">
<source>Last month</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pipes/custom-date.pipe.ts</context>
<context context-type="linenumber">19</context>
</context-group>
</trans-unit>
<trans-unit id="1158628882375251480" datatype="html"> <trans-unit id="1158628882375251480" datatype="html">
<source>%s months ago</source> <source>%s months ago</source>
<context-group purpose="location"> <context-group purpose="location">

View File

@ -29,10 +29,17 @@
<input class="form-control" placeholder="yyyy-mm-dd" <input class="form-control" placeholder="yyyy-mm-dd"
[(ngModel)]="atom.value" [(ngModel)]="atom.value"
ngbDatepicker ngbDatepicker
#d="ngbDatepicker" /> #d="ngbDatepicker"
[footerTemplate]="datePickerFooterTemplate" />
<button class="btn btn-sm btn-outline-secondary rounded-end" (click)="d.toggle()" type="button"> <button class="btn btn-sm btn-outline-secondary rounded-end" (click)="d.toggle()" type="button">
<i-bs name="calendar-event"></i-bs> <i-bs name="calendar-event"></i-bs>
</button> </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) { } @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" [disabled]="disabled"> <input class="w-25 form-control rounded-end" type="number" [(ngModel)]="atom.value" [disabled]="disabled">
} @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Boolean) { } @else if (getCustomFieldByID(atom.field)?.data_type === CustomFieldDataType.Boolean) {

View File

@ -41,3 +41,9 @@
min-width: 140px; min-width: 140px;
} }
} }
.btn-group-xs {
> .btn {
border-radius: 0.15rem;
}
}

View File

@ -241,6 +241,8 @@ export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPerm
customFields: CustomField[] = [] customFields: CustomField[] = []
public readonly today: string = new Date().toISOString().split('T')[0]
constructor(protected customFieldsService: CustomFieldsService) { constructor(protected customFieldsService: CustomFieldsService) {
super() super()
this.selectionModel = new CustomFieldQueriesModel() this.selectionModel = new CustomFieldQueriesModel()

View File

@ -1,5 +1,5 @@
<div class="btn-group w-100" ngbDropdown role="group" [popperOptions]="popperOptions"> <div class="btn-group w-100" ngbDropdown role="group" [popperOptions]="popperOptions">
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="createdDateBefore || createdDateAfter ? 'btn-primary' : 'btn-outline-primary'" [disabled]="disabled"> <button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="createdDateTo || createdDateFrom ? 'btn-primary' : 'btn-outline-primary'" [disabled]="disabled">
<i-bs width="1em" height="1em" name="calendar-event-fill"></i-bs> <i-bs width="1em" height="1em" name="calendar-event-fill"></i-bs>
<div class="d-none d-sm-inline">&nbsp;{{title}}</div> <div class="d-none d-sm-inline">&nbsp;{{title}}</div>
<pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge><span class="visually-hidden">selected</span> <pngx-clearable-badge [selected]="isActive" (cleared)="reset()"></pngx-clearable-badge><span class="visually-hidden">selected</span>
@ -31,40 +31,52 @@
<div class="list-group-item d-flex p-2" role="menuitem"> <div class="list-group-item d-flex p-2" role="menuitem">
<div class="selected-icon"> <div class="selected-icon">
@if (createdDateAfter) { @if (createdDateFrom) {
<a class="text-light focus-variants" href="javascript:void(0)" (click)="clearCreatedAfter()"> <a class="text-light focus-variants" href="javascript:void(0)" (click)="clearCreatedFrom()">
<i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs> <i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs>
<i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs> <i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs>
</a> </a>
} }
</div> </div>
<div class="input-group input-group-sm small ps-1 pe-2"> <div class="input-group input-group-sm small ps-1 pe-2">
<span class="input-group-text w-25 small text-muted" i18n>After</span> <span class="input-group-text w-25 small text-muted" i18n>From</span>
<input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)" <input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="createdDateAfter" ngbDatepicker #createdDateAfterPicker="ngbDatepicker"> maxlength="10" [(ngModel)]="createdDateFrom" ngbDatepicker #createdDateFromPicker="ngbDatepicker" [footerTemplate]="createdFromFooterTemplate">
<button class="btn btn-outline-secondary" (click)="createdDateAfterPicker.toggle()" type="button"> <button class="btn btn-outline-secondary" (click)="createdDateFromPicker.toggle()" type="button">
<i-bs width="1em" height="1em" name="calendar"></i-bs> <i-bs width="1em" height="1em" name="calendar"></i-bs>
</button> </button>
<ng-template #createdFromFooterTemplate>
<div class="btn-group-xs border-top p-2 d-flex">
<button class="btn btn-primary" (click)="createdDateFrom = today; onChangeDebounce()" i18n>Today</button>
<button class="btn btn-secondary ms-auto" (click)="createdDateFromPicker.close()" i18n>Close</button>
</div>
</ng-template>
</div> </div>
</div> </div>
<div class="list-group-item d-flex p-2" role="menuitem"> <div class="list-group-item d-flex p-2" role="menuitem">
<div class="selected-icon"> <div class="selected-icon">
@if (createdDateBefore) { @if (createdDateTo) {
<a class="text-light focus-variants" href="javascript:void(0)" (click)="clearCreatedBefore()"> <a class="text-light focus-variants" href="javascript:void(0)" (click)="clearCreatedTo()">
<i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs> <i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs>
<i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs> <i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs>
</a> </a>
} }
</div> </div>
<div class="input-group input-group-sm small ps-1 pe-2"> <div class="input-group input-group-sm small ps-1 pe-2">
<span class="input-group-text w-25 small text-muted" i18n>Before</span> <span class="input-group-text w-25 small text-muted" i18n>To</span>
<input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)" <input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="createdDateBefore" ngbDatepicker #createdDateBeforePicker="ngbDatepicker"> maxlength="10" [(ngModel)]="createdDateTo" ngbDatepicker #createdDateToPicker="ngbDatepicker" [footerTemplate]="createdToFooterTemplate">
<button class="btn btn-outline-secondary" (click)="createdDateBeforePicker.toggle()" type="button"> <button class="btn btn-outline-secondary" (click)="createdDateToPicker.toggle()" type="button">
<i-bs width="1em" height="1em" name="calendar"></i-bs> <i-bs width="1em" height="1em" name="calendar"></i-bs>
</button> </button>
<ng-template #createdToFooterTemplate>
<div class="btn-group-xs border-top p-2 d-flex">
<button class="btn btn-primary" (click)="createdDateTo = today; onChangeDebounce()" i18n>Today</button>
<button class="btn btn-secondary ms-auto" (click)="createdDateToPicker.close()" i18n>Close</button>
</div>
</ng-template>
</div> </div>
</div> </div>
@ -95,40 +107,52 @@
<div class="list-group-item d-flex p-2" role="menuitem"> <div class="list-group-item d-flex p-2" role="menuitem">
<div class="selected-icon"> <div class="selected-icon">
@if (addedDateAfter) { @if (addedDateFrom) {
<a class="text-light focus-variants" href="javascript:void(0)" (click)="clearAddedAfter()"> <a class="text-light focus-variants" href="javascript:void(0)" (click)="clearAddedFrom()">
<i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs> <i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs>
<i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs> <i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs>
</a> </a>
} }
</div> </div>
<div class="input-group input-group-sm small ps-1 pe-2"> <div class="input-group input-group-sm small ps-1 pe-2">
<span class="input-group-text w-25 small text-muted" i18n>After</span> <span class="input-group-text w-25 small text-muted" i18n>From</span>
<input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)" <input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="addedDateAfter" ngbDatepicker #addedDateAfterPicker="ngbDatepicker"> maxlength="10" [(ngModel)]="addedDateFrom" ngbDatepicker #addedDateFromPicker="ngbDatepicker" [footerTemplate]="addedFromFooterTemplate">
<button class="btn btn-outline-secondary" (click)="addedDateAfterPicker.toggle()" type="button"> <button class="btn btn-outline-secondary" (click)="addedDateFromPicker.toggle()" type="button">
<i-bs width="1em" height="1em" name="calendar"></i-bs> <i-bs width="1em" height="1em" name="calendar"></i-bs>
</button> </button>
<ng-template #addedFromFooterTemplate>
<div class="btn-group-xs border-top p-2 d-flex">
<button class="btn btn-primary" (click)="addedDateFrom = today; onChangeDebounce()" i18n>Today</button>
<button class="btn btn-secondary ms-auto" (click)="addedDateFromPicker.close()" i18n>Close</button>
</div>
</ng-template>
</div> </div>
</div> </div>
<div class="list-group-item d-flex p-2" role="menuitem"> <div class="list-group-item d-flex p-2" role="menuitem">
<div class="selected-icon"> <div class="selected-icon">
@if (addedDateBefore) { @if (addedDateTo) {
<a class="text-light focus-variants" href="javascript:void(0)" (click)="clearAddedBefore()"> <a class="text-light focus-variants" href="javascript:void(0)" (click)="clearAddedTo()">
<i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs> <i-bs width="1em" height="1em" name="check" class="variant-unfocused"></i-bs>
<i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs> <i-bs width="1em" height="1em" name="x" class="variant-focused text-primary"></i-bs>
</a> </a>
} }
</div> </div>
<div class="input-group input-group-sm small ps-1 pe-2"> <div class="input-group input-group-sm small ps-1 pe-2">
<span class="input-group-text w-25 small text-muted" i18n>Before</span> <span class="input-group-text w-25 small text-muted" i18n>To</span>
<input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)" <input class="form-control small" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="addedDateBefore" ngbDatepicker #addedDateBeforePicker="ngbDatepicker"> maxlength="10" [(ngModel)]="addedDateTo" ngbDatepicker #addedDateToPicker="ngbDatepicker" [footerTemplate]="addedToFooterTemplate">
<button class="btn btn-outline-secondary" (click)="addedDateBeforePicker.toggle()" type="button"> <button class="btn btn-outline-secondary" (click)="addedDateToPicker.toggle()" type="button">
<i-bs width="1em" height="1em" name="calendar"></i-bs> <i-bs width="1em" height="1em" name="calendar"></i-bs>
</button> </button>
<ng-template #addedToFooterTemplate>
<div class="btn-group-xs border-top p-2 d-flex">
<button class="btn btn-primary" (click)="addedDateTo = today; onChangeDebounce()" i18n>Today</button>
<button class="btn btn-secondary ms-auto" (click)="addedDateToPicker.close()" i18n>Close</button>
</div>
</ng-template>
</div> </div>
</div> </div>

View File

@ -41,3 +41,9 @@
} }
} }
} }
.btn-group-xs {
> .btn {
border-radius: 0.15rem;
}
}

View File

@ -61,7 +61,7 @@ describe('DatesDropdownComponent', () => {
it('should support date input, emit change', fakeAsync(() => { it('should support date input, emit change', fakeAsync(() => {
let result: string let result: string
component.createdDateAfterChange.subscribe((date) => (result = date)) component.createdDateFromChange.subscribe((date) => (result = date))
const input: HTMLInputElement = fixture.nativeElement.querySelector('input') const input: HTMLInputElement = fixture.nativeElement.querySelector('input')
input.value = '5/30/2023' input.value = '5/30/2023'
input.dispatchEvent(new Event('change')) input.dispatchEvent(new Event('change'))
@ -83,68 +83,68 @@ describe('DatesDropdownComponent', () => {
let result: DateSelection let result: DateSelection
component.datesSet.subscribe((date) => (result = date)) component.datesSet.subscribe((date) => (result = date))
component.setCreatedRelativeDate(null) component.setCreatedRelativeDate(null)
component.setCreatedRelativeDate(RelativeDate.LAST_7_DAYS) component.setCreatedRelativeDate(RelativeDate.WITHIN_1_WEEK)
component.setAddedRelativeDate(null) component.setAddedRelativeDate(null)
component.setAddedRelativeDate(RelativeDate.LAST_7_DAYS) component.setAddedRelativeDate(RelativeDate.WITHIN_1_WEEK)
tick(500) tick(500)
expect(result).toEqual({ expect(result).toEqual({
createdAfter: null, createdFrom: null,
createdBefore: null, createdTo: null,
createdRelativeDateID: RelativeDate.LAST_7_DAYS, createdRelativeDateID: RelativeDate.WITHIN_1_WEEK,
addedAfter: null, addedFrom: null,
addedBefore: null, addedTo: null,
addedRelativeDateID: RelativeDate.LAST_7_DAYS, addedRelativeDateID: RelativeDate.WITHIN_1_WEEK,
}) })
})) }))
it('should support report if active', () => { it('should support report if active', () => {
component.createdRelativeDate = RelativeDate.LAST_7_DAYS component.createdRelativeDate = RelativeDate.WITHIN_1_WEEK
expect(component.isActive).toBeTruthy() expect(component.isActive).toBeTruthy()
component.createdRelativeDate = null component.createdRelativeDate = null
component.createdDateAfter = '2023-05-30' component.createdDateFrom = '2023-05-30'
expect(component.isActive).toBeTruthy() expect(component.isActive).toBeTruthy()
component.createdDateAfter = null component.createdDateFrom = null
component.createdDateBefore = '2023-05-30' component.createdDateTo = '2023-05-30'
expect(component.isActive).toBeTruthy() expect(component.isActive).toBeTruthy()
component.createdDateBefore = null component.createdDateTo = null
component.addedRelativeDate = RelativeDate.LAST_7_DAYS component.addedRelativeDate = RelativeDate.WITHIN_1_WEEK
expect(component.isActive).toBeTruthy() expect(component.isActive).toBeTruthy()
component.addedRelativeDate = null component.addedRelativeDate = null
component.addedDateAfter = '2023-05-30' component.addedDateFrom = '2023-05-30'
expect(component.isActive).toBeTruthy() expect(component.isActive).toBeTruthy()
component.addedDateAfter = null component.addedDateFrom = null
component.addedDateBefore = '2023-05-30' component.addedDateTo = '2023-05-30'
expect(component.isActive).toBeTruthy() expect(component.isActive).toBeTruthy()
component.addedDateBefore = null component.addedDateTo = null
expect(component.isActive).toBeFalsy() expect(component.isActive).toBeFalsy()
}) })
it('should support reset', () => { it('should support reset', () => {
component.createdDateAfter = '2023-05-30' component.createdDateFrom = '2023-05-30'
component.reset() component.reset()
expect(component.createdDateAfter).toBeNull() expect(component.createdDateFrom).toBeNull()
}) })
it('should support clearAfter', () => { it('should support clearFrom', () => {
component.createdDateAfter = '2023-05-30' component.createdDateFrom = '2023-05-30'
component.clearCreatedAfter() component.clearCreatedFrom()
expect(component.createdDateAfter).toBeNull() expect(component.createdDateFrom).toBeNull()
component.addedDateAfter = '2023-05-30' component.addedDateFrom = '2023-05-30'
component.clearAddedAfter() component.clearAddedFrom()
expect(component.addedDateAfter).toBeNull() expect(component.addedDateFrom).toBeNull()
}) })
it('should support clearBefore', () => { it('should support clearTo', () => {
component.createdDateBefore = '2023-05-30' component.createdDateTo = '2023-05-30'
component.clearCreatedBefore() component.clearCreatedTo()
expect(component.createdDateBefore).toBeNull() expect(component.createdDateTo).toBeNull()
component.addedDateBefore = '2023-05-30' component.addedDateTo = '2023-05-30'
component.clearAddedBefore() component.clearAddedTo()
expect(component.addedDateBefore).toBeNull() expect(component.addedDateTo).toBeNull()
}) })
it('should limit keyboard events', () => { it('should limit keyboard events', () => {

View File

@ -23,19 +23,19 @@ import { popperOptionsReenablePreventOverflow } from 'src/app/utils/popper-optio
import { ClearableBadgeComponent } from '../clearable-badge/clearable-badge.component' import { ClearableBadgeComponent } from '../clearable-badge/clearable-badge.component'
export interface DateSelection { export interface DateSelection {
createdBefore?: string createdTo?: string
createdAfter?: string createdFrom?: string
createdRelativeDateID?: number createdRelativeDateID?: number
addedBefore?: string addedTo?: string
addedAfter?: string addedFrom?: string
addedRelativeDateID?: number addedRelativeDateID?: number
} }
export enum RelativeDate { export enum RelativeDate {
LAST_7_DAYS = 0, WITHIN_1_WEEK = 0,
LAST_MONTH = 1, WITHIN_1_MONTH = 1,
LAST_3_MONTHS = 2, WITHIN_3_MONTHS = 2,
LAST_YEAR = 3, WITHIN_1_YEAR = 3,
} }
@Component({ @Component({
@ -63,23 +63,23 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
relativeDates = [ relativeDates = [
{ {
id: RelativeDate.LAST_7_DAYS, id: RelativeDate.WITHIN_1_WEEK,
name: $localize`Last 7 days`, name: $localize`Within 1 week`,
date: new Date().setDate(new Date().getDate() - 7), date: new Date().setDate(new Date().getDate() - 7),
}, },
{ {
id: RelativeDate.LAST_MONTH, id: RelativeDate.WITHIN_1_MONTH,
name: $localize`Last month`, name: $localize`Within 1 month`,
date: new Date().setMonth(new Date().getMonth() - 1), date: new Date().setMonth(new Date().getMonth() - 1),
}, },
{ {
id: RelativeDate.LAST_3_MONTHS, id: RelativeDate.WITHIN_3_MONTHS,
name: $localize`Last 3 months`, name: $localize`Within 3 months`,
date: new Date().setMonth(new Date().getMonth() - 3), date: new Date().setMonth(new Date().getMonth() - 3),
}, },
{ {
id: RelativeDate.LAST_YEAR, id: RelativeDate.WITHIN_1_YEAR,
name: $localize`Last year`, name: $localize`Within 1 year`,
date: new Date().setFullYear(new Date().getFullYear() - 1), date: new Date().setFullYear(new Date().getFullYear() - 1),
}, },
] ]
@ -88,16 +88,16 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
// created // created
@Input() @Input()
createdDateBefore: string createdDateTo: string
@Output() @Output()
createdDateBeforeChange = new EventEmitter<string>() createdDateToChange = new EventEmitter<string>()
@Input() @Input()
createdDateAfter: string createdDateFrom: string
@Output() @Output()
createdDateAfterChange = new EventEmitter<string>() createdDateFromChange = new EventEmitter<string>()
@Input() @Input()
createdRelativeDate: RelativeDate createdRelativeDate: RelativeDate
@ -107,16 +107,16 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
// added // added
@Input() @Input()
addedDateBefore: string addedDateTo: string
@Output() @Output()
addedDateBeforeChange = new EventEmitter<string>() addedDateToChange = new EventEmitter<string>()
@Input() @Input()
addedDateAfter: string addedDateFrom: string
@Output() @Output()
addedDateAfterChange = new EventEmitter<string>() addedDateFromChange = new EventEmitter<string>()
@Input() @Input()
addedRelativeDate: RelativeDate addedRelativeDate: RelativeDate
@ -133,14 +133,16 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
@Input() @Input()
disabled: boolean = false disabled: boolean = false
public readonly today: string = new Date().toISOString().split('T')[0]
get isActive(): boolean { get isActive(): boolean {
return ( return (
this.createdRelativeDate !== null || this.createdRelativeDate !== null ||
this.createdDateAfter?.length > 0 || this.createdDateFrom?.length > 0 ||
this.createdDateBefore?.length > 0 || this.createdDateTo?.length > 0 ||
this.addedRelativeDate !== null || this.addedRelativeDate !== null ||
this.addedDateAfter?.length > 0 || this.addedDateFrom?.length > 0 ||
this.addedDateBefore?.length > 0 this.addedDateTo?.length > 0
) )
} }
@ -161,42 +163,42 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
} }
reset() { reset() {
this.createdDateBefore = null this.createdDateTo = null
this.createdDateAfter = null this.createdDateFrom = null
this.createdRelativeDate = null this.createdRelativeDate = null
this.addedDateBefore = null this.addedDateTo = null
this.addedDateAfter = null this.addedDateFrom = null
this.addedRelativeDate = null this.addedRelativeDate = null
this.onChange() this.onChange()
} }
setCreatedRelativeDate(rd: RelativeDate) { setCreatedRelativeDate(rd: RelativeDate) {
this.createdDateBefore = null this.createdDateTo = null
this.createdDateAfter = null this.createdDateFrom = null
this.createdRelativeDate = this.createdRelativeDate == rd ? null : rd this.createdRelativeDate = this.createdRelativeDate == rd ? null : rd
this.onChange() this.onChange()
} }
setAddedRelativeDate(rd: RelativeDate) { setAddedRelativeDate(rd: RelativeDate) {
this.addedDateBefore = null this.addedDateTo = null
this.addedDateAfter = null this.addedDateFrom = null
this.addedRelativeDate = this.addedRelativeDate == rd ? null : rd this.addedRelativeDate = this.addedRelativeDate == rd ? null : rd
this.onChange() this.onChange()
} }
onChange() { onChange() {
this.createdDateBeforeChange.emit(this.createdDateBefore) this.createdDateToChange.emit(this.createdDateTo)
this.createdDateAfterChange.emit(this.createdDateAfter) this.createdDateFromChange.emit(this.createdDateFrom)
this.createdRelativeDateChange.emit(this.createdRelativeDate) this.createdRelativeDateChange.emit(this.createdRelativeDate)
this.addedDateBeforeChange.emit(this.addedDateBefore) this.addedDateToChange.emit(this.addedDateTo)
this.addedDateAfterChange.emit(this.addedDateAfter) this.addedDateFromChange.emit(this.addedDateFrom)
this.addedRelativeDateChange.emit(this.addedRelativeDate) this.addedRelativeDateChange.emit(this.addedRelativeDate)
this.datesSet.emit({ this.datesSet.emit({
createdAfter: this.createdDateAfter, createdFrom: this.createdDateFrom,
createdBefore: this.createdDateBefore, createdTo: this.createdDateTo,
createdRelativeDateID: this.createdRelativeDate, createdRelativeDateID: this.createdRelativeDate,
addedAfter: this.addedDateAfter, addedFrom: this.addedDateFrom,
addedBefore: this.addedDateBefore, addedTo: this.addedDateTo,
addedRelativeDateID: this.addedRelativeDate, addedRelativeDateID: this.addedRelativeDate,
}) })
} }
@ -205,30 +207,30 @@ export class DatesDropdownComponent implements OnInit, OnDestroy {
this.createdRelativeDate = null this.createdRelativeDate = null
this.addedRelativeDate = null this.addedRelativeDate = null
this.datesSetDebounce$.next({ this.datesSetDebounce$.next({
createdAfter: this.createdDateAfter, createdAfter: this.createdDateFrom,
createdBefore: this.createdDateBefore, createdBefore: this.createdDateTo,
addedAfter: this.addedDateAfter, addedAfter: this.addedDateFrom,
addedBefore: this.addedDateBefore, addedBefore: this.addedDateTo,
}) })
} }
clearCreatedBefore() { clearCreatedTo() {
this.createdDateBefore = null this.createdDateTo = null
this.onChange() this.onChange()
} }
clearCreatedAfter() { clearCreatedFrom() {
this.createdDateAfter = null this.createdDateFrom = null
this.onChange() this.onChange()
} }
clearAddedBefore() { clearAddedTo() {
this.addedDateBefore = null this.addedDateTo = null
this.onChange() this.onChange()
} }
clearAddedAfter() { clearAddedFrom() {
this.addedDateAfter = null this.addedDateFrom = null
this.onChange() this.onChange()
} }

View File

@ -12,10 +12,16 @@
<div class="input-group" [class.is-invalid]="error"> <div class="input-group" [class.is-invalid]="error">
<input #inputField class="form-control" [class.is-invalid]="error" [placeholder]="placeholder" [id]="inputId" maxlength="10" <input #inputField class="form-control" [class.is-invalid]="error" [placeholder]="placeholder" [id]="inputId" maxlength="10"
(dateSelect)="onChange(value)" (change)="onChange(value)" (keypress)="onKeyPress($event)" (paste)="onPaste($event)" (dateSelect)="onChange(value)" (change)="onChange(value)" (keypress)="onKeyPress($event)" (paste)="onPaste($event)"
name="dp" [(ngModel)]="value" ngbDatepicker #datePicker="ngbDatepicker" #datePickerContent="ngModel" [disabled]="disabled"> name="dp" [(ngModel)]="value" ngbDatepicker #datePicker="ngbDatepicker" #datePickerContent="ngModel" [disabled]="disabled" [footerTemplate]="datePickerFooterTemplate">
<button class="btn btn-outline-secondary calendar" (click)="datePicker.toggle()" type="button" [disabled]="disabled"> <button class="btn btn-outline-secondary calendar" (click)="datePicker.toggle()" type="button" [disabled]="disabled">
<i-bs width="1.2em" height="1.2em" name="calendar"></i-bs> <i-bs width="1.2em" height="1.2em" name="calendar"></i-bs>
</button> </button>
<ng-template #datePickerFooterTemplate>
<div class="btn-group-xs border-top p-2 d-flex">
<button type="button" class="btn btn-primary" (click)="value = today; onChange(value); datePicker.close()" i18n>Today</button>
<button type="button" class="btn btn-secondary ms-auto" (click)="datePicker.close()" i18n>Close</button>
</div>
</ng-template>
@if (showFilter) { @if (showFilter) {
<button class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="this.value === null" title="{{ filterButtonTitle }}"> <button class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="this.value === null" title="{{ filterButtonTitle }}">
<i-bs width="1.2em" height="1.2em" name="filter"></i-bs> <i-bs width="1.2em" height="1.2em" name="filter"></i-bs>

View File

@ -0,0 +1,5 @@
.btn-group-xs {
> .btn {
border-radius: 0.15rem;
}
}

View File

@ -62,6 +62,8 @@ export class DateComponent
@Output() @Output()
filterDocuments = new EventEmitter<NgbDateStruct[]>() filterDocuments = new EventEmitter<NgbDateStruct[]>()
public readonly today: string = new Date().toISOString().split('T')[0]
getSuggestions() { getSuggestions() {
return this.suggestions == null return this.suggestions == null
? [] ? []

View File

@ -94,11 +94,11 @@
<pngx-dates-dropdown class="flex-fill fade" [class.show]="show" <pngx-dates-dropdown class="flex-fill fade" [class.show]="show"
title="Dates" i18n-title title="Dates" i18n-title
(datesSet)="updateRules()" (datesSet)="updateRules()"
[(createdDateBefore)]="dateCreatedBefore" [(createdDateTo)]="dateCreatedTo"
[(createdDateAfter)]="dateCreatedAfter" [(createdDateFrom)]="dateCreatedFrom"
[(createdRelativeDate)]="dateCreatedRelativeDate" [(createdRelativeDate)]="dateCreatedRelativeDate"
[(addedDateBefore)]="dateAddedBefore" [(addedDateTo)]="dateAddedTo"
[(addedDateAfter)]="dateAddedAfter" [(addedDateFrom)]="dateAddedFrom"
[(addedRelativeDate)]="dateAddedRelativeDate"> [(addedRelativeDate)]="dateAddedRelativeDate">
</pngx-dates-dropdown> </pngx-dates-dropdown>
<pngx-permissions-filter-dropdown class="flex-fill fade" [class.show]="show" <pngx-permissions-filter-dropdown class="flex-fill fade" [class.show]="show"

View File

@ -32,6 +32,8 @@ import { DocumentType } from 'src/app/data/document-type'
import { import {
FILTER_ADDED_AFTER, FILTER_ADDED_AFTER,
FILTER_ADDED_BEFORE, FILTER_ADDED_BEFORE,
FILTER_ADDED_FROM,
FILTER_ADDED_TO,
FILTER_ASN, FILTER_ASN,
FILTER_ASN_GT, FILTER_ASN_GT,
FILTER_ASN_ISNULL, FILTER_ASN_ISNULL,
@ -39,6 +41,8 @@ import {
FILTER_CORRESPONDENT, FILTER_CORRESPONDENT,
FILTER_CREATED_AFTER, FILTER_CREATED_AFTER,
FILTER_CREATED_BEFORE, FILTER_CREATED_BEFORE,
FILTER_CREATED_FROM,
FILTER_CREATED_TO,
FILTER_CUSTOM_FIELDS_QUERY, FILTER_CUSTOM_FIELDS_QUERY,
FILTER_CUSTOM_FIELDS_TEXT, FILTER_CUSTOM_FIELDS_TEXT,
FILTER_DOCUMENT_TYPE, FILTER_DOCUMENT_TYPE,
@ -465,48 +469,92 @@ describe('FilterEditorComponent', () => {
]) ])
})) }))
it('should ingest filter rules for date created after', fakeAsync(() => { it('should ingest filter rules for date created after and adjust date by 1 day', fakeAsync(() => {
expect(component.dateCreatedAfter).toBeNull() expect(component.dateCreatedFrom).toBeNull()
component.filterRules = [ component.filterRules = [
{ {
rule_type: FILTER_CREATED_AFTER, rule_type: FILTER_CREATED_AFTER,
value: '2023-05-14', value: '2023-05-14',
}, },
] ]
expect(component.dateCreatedAfter).toEqual('2023-05-14') expect(component.dateCreatedFrom).toEqual('2023-05-15')
})) }))
it('should ingest filter rules for date created before', fakeAsync(() => { it('should ingest filter rules for date created from', fakeAsync(() => {
expect(component.dateCreatedBefore).toBeNull() expect(component.dateCreatedFrom).toBeNull()
component.filterRules = [
{
rule_type: FILTER_CREATED_FROM,
value: '2023-05-14',
},
]
expect(component.dateCreatedFrom).toEqual('2023-05-14')
}))
it('should ingest filter rules for date created before and adjust date by 1 day', fakeAsync(() => {
expect(component.dateCreatedTo).toBeNull()
component.filterRules = [ component.filterRules = [
{ {
rule_type: FILTER_CREATED_BEFORE, rule_type: FILTER_CREATED_BEFORE,
value: '2023-05-14', value: '2023-05-14',
}, },
] ]
expect(component.dateCreatedBefore).toEqual('2023-05-14') expect(component.dateCreatedTo).toEqual('2023-05-13')
})) }))
it('should ingest filter rules for date added after', fakeAsync(() => { it('should ingest filter rules for date created to', fakeAsync(() => {
expect(component.dateAddedAfter).toBeNull() expect(component.dateCreatedTo).toBeNull()
component.filterRules = [
{
rule_type: FILTER_CREATED_TO,
value: '2023-05-14',
},
]
expect(component.dateCreatedTo).toEqual('2023-05-14')
}))
it('should ingest filter rules for date added after and adjust date by 1 day', fakeAsync(() => {
expect(component.dateAddedFrom).toBeNull()
component.filterRules = [ component.filterRules = [
{ {
rule_type: FILTER_ADDED_AFTER, rule_type: FILTER_ADDED_AFTER,
value: '2023-05-14', value: '2023-05-14',
}, },
] ]
expect(component.dateAddedAfter).toEqual('2023-05-14') expect(component.dateAddedFrom).toEqual('2023-05-15')
})) }))
it('should ingest filter rules for date added before', fakeAsync(() => { it('should ingest filter rules for date added from', fakeAsync(() => {
expect(component.dateAddedBefore).toBeNull() expect(component.dateAddedFrom).toBeNull()
component.filterRules = [
{
rule_type: FILTER_ADDED_FROM,
value: '2023-05-14',
},
]
expect(component.dateAddedFrom).toEqual('2023-05-14')
}))
it('should ingest filter rules for date added before and adjust date by 1 day', fakeAsync(() => {
expect(component.dateAddedTo).toBeNull()
component.filterRules = [ component.filterRules = [
{ {
rule_type: FILTER_ADDED_BEFORE, rule_type: FILTER_ADDED_BEFORE,
value: '2023-05-14', value: '2023-05-14',
}, },
] ]
expect(component.dateAddedBefore).toEqual('2023-05-14') expect(component.dateAddedTo).toEqual('2023-05-13')
}))
it('should ingest filter rules for date added to', fakeAsync(() => {
expect(component.dateAddedTo).toBeNull()
component.filterRules = [
{
rule_type: FILTER_ADDED_TO,
value: '2023-05-14',
},
]
expect(component.dateAddedTo).toEqual('2023-05-14')
})) }))
it('should ingest filter rules for has all tags', fakeAsync(() => { it('should ingest filter rules for has all tags', fakeAsync(() => {
@ -1464,7 +1512,7 @@ describe('FilterEditorComponent', () => {
]) ])
})) }))
it('should convert user input to correct filter rules on date created after', fakeAsync(() => { it('should convert user input to correct filter rules on date created from', fakeAsync(() => {
const dateCreatedDropdown = fixture.debugElement.queryAll( const dateCreatedDropdown = fixture.debugElement.queryAll(
By.directive(DatesDropdownComponent) By.directive(DatesDropdownComponent)
)[0] )[0]
@ -1473,18 +1521,18 @@ describe('FilterEditorComponent', () => {
dateCreatedAfter.nativeElement.value = '05/14/2023' dateCreatedAfter.nativeElement.value = '05/14/2023'
// dateCreatedAfter.triggerEventHandler('change') // dateCreatedAfter.triggerEventHandler('change')
// TODO: why isn't ngModel triggering this on change? // TODO: why isn't ngModel triggering this on change?
component.dateCreatedAfter = '2023-05-14' component.dateCreatedFrom = '2023-05-14'
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{ {
rule_type: FILTER_CREATED_AFTER, rule_type: FILTER_CREATED_FROM,
value: '2023-05-14', value: '2023-05-14',
}, },
]) ])
})) }))
it('should convert user input to correct filter rules on date created before', fakeAsync(() => { it('should convert user input to correct filter rules on date created to', fakeAsync(() => {
const dateCreatedDropdown = fixture.debugElement.queryAll( const dateCreatedDropdown = fixture.debugElement.queryAll(
By.directive(DatesDropdownComponent) By.directive(DatesDropdownComponent)
)[0] )[0]
@ -1493,12 +1541,12 @@ describe('FilterEditorComponent', () => {
dateCreatedBefore.nativeElement.value = '05/14/2023' dateCreatedBefore.nativeElement.value = '05/14/2023'
// dateCreatedBefore.triggerEventHandler('change') // dateCreatedBefore.triggerEventHandler('change')
// TODO: why isn't ngModel triggering this on change? // TODO: why isn't ngModel triggering this on change?
component.dateCreatedBefore = '2023-05-14' component.dateCreatedTo = '2023-05-14'
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{ {
rule_type: FILTER_CREATED_BEFORE, rule_type: FILTER_CREATED_TO,
value: '2023-05-14', value: '2023-05-14',
}, },
]) ])
@ -1578,12 +1626,12 @@ describe('FilterEditorComponent', () => {
dateAddedAfter.nativeElement.value = '05/14/2023' dateAddedAfter.nativeElement.value = '05/14/2023'
// dateAddedAfter.triggerEventHandler('change') // dateAddedAfter.triggerEventHandler('change')
// TODO: why isn't ngModel triggering this on change? // TODO: why isn't ngModel triggering this on change?
component.dateAddedAfter = '2023-05-14' component.dateAddedFrom = '2023-05-14'
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{ {
rule_type: FILTER_ADDED_AFTER, rule_type: FILTER_ADDED_FROM,
value: '2023-05-14', value: '2023-05-14',
}, },
]) ])
@ -1598,12 +1646,12 @@ describe('FilterEditorComponent', () => {
dateAddedBefore.nativeElement.value = '05/14/2023' dateAddedBefore.nativeElement.value = '05/14/2023'
// dateAddedBefore.triggerEventHandler('change') // dateAddedBefore.triggerEventHandler('change')
// TODO: why isn't ngModel triggering this on change? // TODO: why isn't ngModel triggering this on change?
component.dateAddedBefore = '2023-05-14' component.dateAddedTo = '2023-05-14'
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{ {
rule_type: FILTER_ADDED_BEFORE, rule_type: FILTER_ADDED_TO,
value: '2023-05-14', value: '2023-05-14',
}, },
]) ])

View File

@ -38,6 +38,8 @@ import { FilterRule } from 'src/app/data/filter-rule'
import { import {
FILTER_ADDED_AFTER, FILTER_ADDED_AFTER,
FILTER_ADDED_BEFORE, FILTER_ADDED_BEFORE,
FILTER_ADDED_FROM,
FILTER_ADDED_TO,
FILTER_ASN, FILTER_ASN,
FILTER_ASN_GT, FILTER_ASN_GT,
FILTER_ASN_ISNULL, FILTER_ASN_ISNULL,
@ -45,6 +47,8 @@ import {
FILTER_CORRESPONDENT, FILTER_CORRESPONDENT,
FILTER_CREATED_AFTER, FILTER_CREATED_AFTER,
FILTER_CREATED_BEFORE, FILTER_CREATED_BEFORE,
FILTER_CREATED_FROM,
FILTER_CREATED_TO,
FILTER_CUSTOM_FIELDS_QUERY, FILTER_CUSTOM_FIELDS_QUERY,
FILTER_CUSTOM_FIELDS_TEXT, FILTER_CUSTOM_FIELDS_TEXT,
FILTER_DOCUMENT_TYPE, FILTER_DOCUMENT_TYPE,
@ -133,19 +137,19 @@ const RELATIVE_DATE_QUERY_REGEXP_CREATED = /created:\[([^\]]+)\]/g
const RELATIVE_DATE_QUERY_REGEXP_ADDED = /added:\[([^\]]+)\]/g const RELATIVE_DATE_QUERY_REGEXP_ADDED = /added:\[([^\]]+)\]/g
const RELATIVE_DATE_QUERYSTRINGS = [ const RELATIVE_DATE_QUERYSTRINGS = [
{ {
relativeDate: RelativeDate.LAST_7_DAYS, relativeDate: RelativeDate.WITHIN_1_WEEK,
dateQuery: '-1 week to now', dateQuery: '-1 week to now',
}, },
{ {
relativeDate: RelativeDate.LAST_MONTH, relativeDate: RelativeDate.WITHIN_1_MONTH,
dateQuery: '-1 month to now', dateQuery: '-1 month to now',
}, },
{ {
relativeDate: RelativeDate.LAST_3_MONTHS, relativeDate: RelativeDate.WITHIN_3_MONTHS,
dateQuery: '-3 month to now', dateQuery: '-3 month to now',
}, },
{ {
relativeDate: RelativeDate.LAST_YEAR, relativeDate: RelativeDate.WITHIN_1_YEAR,
dateQuery: '-1 year to now', dateQuery: '-1 year to now',
}, },
] ]
@ -349,10 +353,10 @@ export class FilterEditorComponent
storagePathSelectionModel = new FilterableDropdownSelectionModel() storagePathSelectionModel = new FilterableDropdownSelectionModel()
customFieldQueriesModel = new CustomFieldQueriesModel() customFieldQueriesModel = new CustomFieldQueriesModel()
dateCreatedBefore: string dateCreatedTo: string
dateCreatedAfter: string dateCreatedFrom: string
dateAddedBefore: string dateAddedTo: string
dateAddedAfter: string dateAddedFrom: string
dateCreatedRelativeDate: RelativeDate dateCreatedRelativeDate: RelativeDate
dateAddedRelativeDate: RelativeDate dateAddedRelativeDate: RelativeDate
@ -385,10 +389,10 @@ export class FilterEditorComponent
this.customFieldQueriesModel.clear(false) this.customFieldQueriesModel.clear(false)
this._textFilter = null this._textFilter = null
this._moreLikeId = null this._moreLikeId = null
this.dateAddedBefore = null this.dateAddedTo = null
this.dateAddedAfter = null this.dateAddedFrom = null
this.dateCreatedBefore = null this.dateCreatedTo = null
this.dateCreatedAfter = null this.dateCreatedFrom = null
this.dateCreatedRelativeDate = null this.dateCreatedRelativeDate = null
this.dateAddedRelativeDate = null this.dateAddedRelativeDate = null
this.textFilterModifier = TEXT_FILTER_MODIFIER_EQUALS this.textFilterModifier = TEXT_FILTER_MODIFIER_EQUALS
@ -458,16 +462,40 @@ export class FilterEditorComponent
}) })
break break
case FILTER_CREATED_AFTER: case FILTER_CREATED_AFTER:
this.dateCreatedAfter = rule.value // Old rules require adjusting date by a day
const createdAfter = new Date(rule.value)
createdAfter.setDate(createdAfter.getDate() + 1)
this.dateCreatedFrom = createdAfter.toISOString().split('T')[0]
break break
case FILTER_CREATED_BEFORE: case FILTER_CREATED_BEFORE:
this.dateCreatedBefore = rule.value // Old rules require adjusting date by a day
const createdBefore = new Date(rule.value)
createdBefore.setDate(createdBefore.getDate() - 1)
this.dateCreatedTo = createdBefore.toISOString().split('T')[0]
break break
case FILTER_ADDED_AFTER: case FILTER_ADDED_AFTER:
this.dateAddedAfter = rule.value // Old rules require adjusting date by a day
const addedAfter = new Date(rule.value)
addedAfter.setDate(addedAfter.getDate() + 1)
this.dateAddedFrom = addedAfter.toISOString().split('T')[0]
break break
case FILTER_ADDED_BEFORE: case FILTER_ADDED_BEFORE:
this.dateAddedBefore = rule.value // Old rules require adjusting date by a day
const addedBefore = new Date(rule.value)
addedBefore.setDate(addedBefore.getDate() - 1)
this.dateAddedTo = addedBefore.toISOString().split('T')[0]
break
case FILTER_CREATED_FROM:
this.dateCreatedFrom = rule.value
break
case FILTER_CREATED_TO:
this.dateCreatedTo = rule.value
break
case FILTER_ADDED_FROM:
this.dateAddedFrom = rule.value
break
case FILTER_ADDED_TO:
this.dateAddedTo = rule.value
break break
case FILTER_HAS_TAGS_ALL: case FILTER_HAS_TAGS_ALL:
this.tagSelectionModel.logicalOperator = LogicalOperator.And this.tagSelectionModel.logicalOperator = LogicalOperator.And
@ -814,28 +842,28 @@ export class FilterEditorComponent
value: JSON.stringify(queries[0]), value: JSON.stringify(queries[0]),
}) })
} }
if (this.dateCreatedBefore) { if (this.dateCreatedTo) {
filterRules.push({ filterRules.push({
rule_type: FILTER_CREATED_BEFORE, rule_type: FILTER_CREATED_TO,
value: this.dateCreatedBefore, value: this.dateCreatedTo,
}) })
} }
if (this.dateCreatedAfter) { if (this.dateCreatedFrom) {
filterRules.push({ filterRules.push({
rule_type: FILTER_CREATED_AFTER, rule_type: FILTER_CREATED_FROM,
value: this.dateCreatedAfter, value: this.dateCreatedFrom,
}) })
} }
if (this.dateAddedBefore) { if (this.dateAddedTo) {
filterRules.push({ filterRules.push({
rule_type: FILTER_ADDED_BEFORE, rule_type: FILTER_ADDED_TO,
value: this.dateAddedBefore, value: this.dateAddedTo,
}) })
} }
if (this.dateAddedAfter) { if (this.dateAddedFrom) {
filterRules.push({ filterRules.push({
rule_type: FILTER_ADDED_AFTER, rule_type: FILTER_ADDED_FROM,
value: this.dateAddedAfter, value: this.dateAddedFrom,
}) })
} }
if ( if (

View File

@ -36,6 +36,11 @@ export const FILTER_CREATED_DAY = 12
export const FILTER_ADDED_BEFORE = 13 export const FILTER_ADDED_BEFORE = 13
export const FILTER_ADDED_AFTER = 14 export const FILTER_ADDED_AFTER = 14
export const FILTER_CREATED_TO = 43
export const FILTER_CREATED_FROM = 44
export const FILTER_ADDED_TO = 45
export const FILTER_ADDED_FROM = 46
export const FILTER_MODIFIED_BEFORE = 15 export const FILTER_MODIFIED_BEFORE = 15
export const FILTER_MODIFIED_AFTER = 16 export const FILTER_MODIFIED_AFTER = 16
@ -179,6 +184,18 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
datatype: 'date', datatype: 'date',
multi: false, multi: false,
}, },
{
id: FILTER_CREATED_TO,
filtervar: 'created__date__lte',
datatype: 'date',
multi: false,
},
{
id: FILTER_CREATED_FROM,
filtervar: 'created__date__gte',
datatype: 'date',
multi: false,
},
{ {
id: FILTER_CREATED_YEAR, id: FILTER_CREATED_YEAR,
filtervar: 'created__year', filtervar: 'created__year',
@ -210,6 +227,18 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
datatype: 'date', datatype: 'date',
multi: false, multi: false,
}, },
{
id: FILTER_ADDED_TO,
filtervar: 'added__date__lte',
datatype: 'date',
multi: false,
},
{
id: FILTER_ADDED_FROM,
filtervar: 'added__date__gte',
datatype: 'date',
multi: false,
},
{ {
id: FILTER_MODIFIED_BEFORE, id: FILTER_MODIFIED_BEFORE,
filtervar: 'modified__date__lt', filtervar: 'modified__date__lt',

View File

@ -41,7 +41,19 @@ from documents.models import Tag
CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"] CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"]
ID_KWARGS = ["in", "exact"] ID_KWARGS = ["in", "exact"]
INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"] INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"]
DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"] DATE_KWARGS = [
"year",
"month",
"day",
"date__gt",
"date__gte",
"gt",
"gte",
"date__lt",
"date__lte",
"lt",
"lte",
]
CUSTOM_FIELD_QUERY_MAX_DEPTH = 10 CUSTOM_FIELD_QUERY_MAX_DEPTH = 10
CUSTOM_FIELD_QUERY_MAX_ATOMS = 20 CUSTOM_FIELD_QUERY_MAX_ATOMS = 20

View File

@ -0,0 +1,69 @@
# Generated by Django 5.1.4 on 2025-02-06 05:54
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1061_workflowactionwebhook_as_json"),
]
operations = [
migrations.AlterField(
model_name="savedviewfilterrule",
name="rule_type",
field=models.PositiveIntegerField(
choices=[
(0, "title contains"),
(1, "content contains"),
(2, "ASN is"),
(3, "correspondent is"),
(4, "document type is"),
(5, "is in inbox"),
(6, "has tag"),
(7, "has any tag"),
(8, "created before"),
(9, "created after"),
(10, "created year is"),
(11, "created month is"),
(12, "created day is"),
(13, "added before"),
(14, "added after"),
(15, "modified before"),
(16, "modified after"),
(17, "does not have tag"),
(18, "does not have ASN"),
(19, "title or content contains"),
(20, "fulltext query"),
(21, "more like this"),
(22, "has tags in"),
(23, "ASN greater than"),
(24, "ASN less than"),
(25, "storage path is"),
(26, "has correspondent in"),
(27, "does not have correspondent in"),
(28, "has document type in"),
(29, "does not have document type in"),
(30, "has storage path in"),
(31, "does not have storage path in"),
(32, "owner is"),
(33, "has owner in"),
(34, "does not have owner"),
(35, "does not have owner in"),
(36, "has custom field value"),
(37, "is shared by me"),
(38, "has custom fields"),
(39, "has custom field in"),
(40, "does not have custom field in"),
(41, "does not have custom field"),
(42, "custom fields query"),
(43, "created to"),
(44, "created from"),
(45, "added to"),
(46, "added from"),
],
verbose_name="rule type",
),
),
]

View File

@ -522,6 +522,10 @@ class SavedViewFilterRule(models.Model):
(40, _("does not have custom field in")), (40, _("does not have custom field in")),
(41, _("does not have custom field")), (41, _("does not have custom field")),
(42, _("custom fields query")), (42, _("custom fields query")),
(43, _("created to")),
(44, _("created from")),
(45, _("added to")),
(46, _("added from")),
] ]
saved_view = models.ForeignKey( saved_view = models.ForeignKey(