Allow filtering on multiple correspondents, doctypes, storage paths

Preserve 'Not assigned' option
Fix default logical operator
Update frontend strings
Fix radio button name overlaps
Use include / exclude with multi-select for OneToOne objects
This commit is contained in:
shamoon
2023-03-10 14:53:32 -08:00
parent 1008b6c1f5
commit 4003f64b49
15 changed files with 483 additions and 188 deletions

View File

@@ -770,7 +770,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/permissions-dialog/permissions-dialog.component.html</context>
<context context-type="linenumber">17</context>
<context context-type="linenumber">21</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -1015,7 +1015,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/permissions-dialog/permissions-dialog.component.html</context>
<context context-type="linenumber">16</context>
<context context-type="linenumber">20</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/select-dialog/select-dialog.component.html</context>
@@ -1498,7 +1498,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">208</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
@@ -1787,25 +1787,39 @@
<context context-type="linenumber">18</context>
</context-group>
</trans-unit>
<trans-unit id="6381578200008167206" datatype="html">
<source>Include</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
<context context-type="linenumber">24</context>
</context-group>
</trans-unit>
<trans-unit id="5668077948386857930" datatype="html">
<source>Exclude</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="4391289919356861627" datatype="html">
<source>Apply</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
<context context-type="linenumber">32</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="7780041345210191160" datatype="html">
<source>Click again to exclude items.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.html</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">46</context>
</context-group>
</trans-unit>
<trans-unit id="7593728289020204896" datatype="html">
<source>Not assigned</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts</context>
<context context-type="linenumber">262</context>
<context context-type="linenumber">321</context>
</context-group>
<note priority="1" from="description">Filter drop down element to filter for documents with no correspondent/type/tag assigned</note>
</trans-unit>
@@ -1974,6 +1988,45 @@
<context context-type="linenumber">12</context>
</context-group>
</trans-unit>
<trans-unit id="3894950702316166331" datatype="html">
<source>Loading...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/permissions-dialog/permissions-dialog.component.html</context>
<context context-type="linenumber">18</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/dashboard.component.html</context>
<context context-type="linenumber">26</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">95</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">230</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">320</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">406</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.html</context>
<context context-type="linenumber">19</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.html</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="8105421668262723483" datatype="html">
<source>Set Permissions</source>
<context-group purpose="location">
@@ -1985,7 +2038,7 @@
<source>Note that permissions set here will override any existing permissions</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/permissions-dialog/permissions-dialog.component.ts</context>
<context context-type="linenumber">41</context>
<context context-type="linenumber">43</context>
</context-group>
</trans-unit>
<trans-unit id="8650499415827640724" datatype="html">
@@ -2049,41 +2102,6 @@
<context context-type="linenumber">20</context>
</context-group>
</trans-unit>
<trans-unit id="3894950702316166331" datatype="html">
<source>Loading...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/dashboard.component.html</context>
<context context-type="linenumber">26</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">95</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">230</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">320</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">406</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.html</context>
<context context-type="linenumber">19</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.html</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="1865646076514070962" datatype="html">
<source>Hello <x id="PH" equiv-text="this.settingsService.displayName"/>, welcome to Paperless-ngx</source>
<context-group purpose="location">
@@ -2148,7 +2166,7 @@
</context-group>
<context-group purpose="location">
<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">172</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@@ -2649,64 +2667,64 @@
<source>Error retrieving suggestions</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">319</context>
<context context-type="linenumber">325</context>
</context-group>
</trans-unit>
<trans-unit id="448882439049417053" datatype="html">
<source>Error saving document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">432</context>
<context context-type="linenumber">439</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">476</context>
<context context-type="linenumber">483</context>
</context-group>
</trans-unit>
<trans-unit id="9021887951960049161" datatype="html">
<source>Confirm delete</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">505</context>
<context context-type="linenumber">512</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">209</context>
<context context-type="linenumber">204</context>
</context-group>
</trans-unit>
<trans-unit id="5382975254277698192" datatype="html">
<source>Do you really want to delete document &quot;<x id="PH" equiv-text="this.document.title"/>&quot;?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">506</context>
<context context-type="linenumber">513</context>
</context-group>
</trans-unit>
<trans-unit id="6691075929777935948" datatype="html">
<source>The files for this document will be deleted permanently. This operation cannot be undone.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">507</context>
<context context-type="linenumber">514</context>
</context-group>
</trans-unit>
<trans-unit id="719892092227206532" datatype="html">
<source>Delete document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">509</context>
<context context-type="linenumber">516</context>
</context-group>
</trans-unit>
<trans-unit id="1844801255494293730" datatype="html">
<source>Error deleting document: <x id="PH" equiv-text="JSON.stringify(error)"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">525</context>
<context context-type="linenumber">532</context>
</context-group>
</trans-unit>
<trans-unit id="7362691899087997122" datatype="html">
<source>Redo OCR confirm</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">545</context>
<context context-type="linenumber">552</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -2717,14 +2735,14 @@
<source>This operation will permanently redo OCR for this document.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">546</context>
<context context-type="linenumber">553</context>
</context-group>
</trans-unit>
<trans-unit id="5641451190833696892" datatype="html">
<source>This operation cannot be undone.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">547</context>
<context context-type="linenumber">554</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -2755,7 +2773,7 @@
<source>Proceed</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">549</context>
<context context-type="linenumber">556</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -2782,7 +2800,7 @@
<source>Redo OCR operation will begin in the background. Close and re-open or reload this document after the operation has completed to see new content.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">557</context>
<context context-type="linenumber">564</context>
</context-group>
</trans-unit>
<trans-unit id="8008978164775353960" datatype="html">
@@ -2791,7 +2809,7 @@
)"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">568,570</context>
<context context-type="linenumber">575,577</context>
</context-group>
</trans-unit>
<trans-unit id="6857598786757174736" datatype="html">
@@ -3305,7 +3323,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">167</context>
<context context-type="linenumber">177</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@@ -3359,112 +3377,112 @@
<source>Correspondent: <x id="PH" equiv-text="this.correspondents.find((c) =&gt; c.id == +rule.value)?.name"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">98,100</context>
<context context-type="linenumber">108,110</context>
</context-group>
</trans-unit>
<trans-unit id="8170755470576301659" datatype="html">
<source>Without correspondent</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">102</context>
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8705701325879965907" datatype="html">
<source>Type: <x id="PH" equiv-text="this.documentTypes.find((dt) =&gt; dt.id == +rule.value)?.name"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">107,109</context>
<context context-type="linenumber">117,119</context>
</context-group>
</trans-unit>
<trans-unit id="4362173610367509215" datatype="html">
<source>Without document type</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">111</context>
<context context-type="linenumber">121</context>
</context-group>
</trans-unit>
<trans-unit id="8180755793012580465" datatype="html">
<source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)?.name"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">115,117</context>
<context context-type="linenumber">125,127</context>
</context-group>
</trans-unit>
<trans-unit id="6494566478302448576" datatype="html">
<source>Without any tag</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">121</context>
<context context-type="linenumber">131</context>
</context-group>
</trans-unit>
<trans-unit id="6523384805359286307" datatype="html">
<source>Title: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">135</context>
</context-group>
</trans-unit>
<trans-unit id="1872523635812236432" datatype="html">
<source>ASN: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">128</context>
<context context-type="linenumber">138</context>
</context-group>
</trans-unit>
<trans-unit id="3100631071441658964" datatype="html">
<source>Title &amp; content</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">165</context>
<context context-type="linenumber">175</context>
</context-group>
</trans-unit>
<trans-unit id="1010505078885609376" datatype="html">
<source>Advanced search</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">170</context>
<context context-type="linenumber">180</context>
</context-group>
</trans-unit>
<trans-unit id="2649431021108393503" datatype="html">
<source>More like</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">176</context>
<context context-type="linenumber">186</context>
</context-group>
</trans-unit>
<trans-unit id="3697582909018473071" datatype="html">
<source>equals</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">195</context>
<context context-type="linenumber">205</context>
</context-group>
</trans-unit>
<trans-unit id="5325481293405718739" datatype="html">
<source>is empty</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">199</context>
<context context-type="linenumber">209</context>
</context-group>
</trans-unit>
<trans-unit id="6166785695326182482" datatype="html">
<source>is not empty</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">203</context>
<context context-type="linenumber">213</context>
</context-group>
</trans-unit>
<trans-unit id="4686622206659266699" datatype="html">
<source>greater than</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">217</context>
</context-group>
</trans-unit>
<trans-unit id="8014012170270529279" datatype="html">
<source>less than</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">211</context>
<context context-type="linenumber">221</context>
</context-group>
</trans-unit>
<trans-unit id="7210076240260527720" datatype="html">
@@ -3699,50 +3717,50 @@
<source>Error occurred while creating <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="activeModal.componentInstance.error"/>.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">142,144</context>
<context context-type="linenumber">142</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">155,157</context>
<context context-type="linenumber">153,155</context>
</context-group>
</trans-unit>
<trans-unit id="211408744872436427" datatype="html">
<source>Successfully created <x id="PH" equiv-text="this.typeName"/>.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">149</context>
<context context-type="linenumber">147</context>
</context-group>
</trans-unit>
<trans-unit id="6151710751857751783" datatype="html">
<source>Error occurred while saving <x id="PH" equiv-text="this.typeName"/> : <x id="PH_1" equiv-text="activeModal.componentInstance.error"/>.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">173,175</context>
<context context-type="linenumber">171</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">187,189</context>
<context context-type="linenumber">182,184</context>
</context-group>
</trans-unit>
<trans-unit id="2541368547549828690" datatype="html">
<source>Successfully updated <x id="PH" equiv-text="this.typeName"/>.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">181</context>
<context context-type="linenumber">176</context>
</context-group>
</trans-unit>
<trans-unit id="4012132330507560812" datatype="html">
<source>Do you really want to delete the <x id="PH" equiv-text="this.typeName"/>?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">191</context>
</context-group>
</trans-unit>
<trans-unit id="8371896857609524947" datatype="html">
<source>Associated documents will not be deleted.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">211</context>
<context context-type="linenumber">206</context>
</context-group>
</trans-unit>
<trans-unit id="5467489005440577210" datatype="html">
@@ -3751,7 +3769,7 @@
)"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
<context context-type="linenumber">224,226</context>
<context context-type="linenumber">219,221</context>
</context-group>
</trans-unit>
<trans-unit id="1685061484835793745" datatype="html">

View File

@@ -1,21 +1,29 @@
<div class="btn-group w-100" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #dropdown="ngbDropdown">
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="!editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'" [disabled]="disabled">
<button class="btn btn-sm" id="dropdown_{{name}}" ngbDropdownToggle [ngClass]="!editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'" [disabled]="disabled">
<svg class="toolbaricon" fill="currentColor">
<use attr.xlink:href="assets/bootstrap-icons.svg#{{icon}}" />
</svg>
<div class="d-none d-sm-inline">&nbsp;{{title}}</div>
<ng-container *ngIf="!editing && selectionModel.totalCount > 0">
<app-clearable-badge [number]="multiple ? selectionModel.totalCount : undefined" [selected]="!multiple && selectionModel.selectionSize() > 0" (cleared)="reset()"></app-clearable-badge>
<app-clearable-badge [number]="selectionModel.totalCount" [selected]="selectionModel.selectionSize() > 0" (cleared)="reset()"></app-clearable-badge>
</ng-container>
</button>
<div class="dropdown-menu py-0 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown{{title}}">
<div class="dropdown-menu py-0 shadow" ngbDropdownMenu attr.aria-labelledby="dropdown_{{name}}">
<div class="list-group list-group-flush">
<div *ngIf="!editing && multiple" class="list-group-item d-flex">
<div class="btn-group btn-group-xs flex-fill">
<input [(ngModel)]="selectionModel.logicalOperator" [disabled]="!operatorToggleEnabled" (ngModelChange)="selectionModel.toggleOperator()" type="radio" class="btn-check" id="logicalOperatorAnd" value="and">
<label class="btn btn-outline-primary" for="logicalOperatorAnd" i18n>All</label>
<input [(ngModel)]="selectionModel.logicalOperator" [disabled]="!operatorToggleEnabled" (ngModelChange)="selectionModel.toggleOperator()" type="radio" class="btn-check" id="logicalOperatorOr" value="or">
<label class="btn btn-outline-primary" for="logicalOperatorOr" i18n>Any</label>
<div *ngIf="!editing && manyToOne" class="list-group-item d-flex">
<div class="btn-group btn-group-xs flex-fill" role="group">
<input [(ngModel)]="selectionModel.logicalOperator" [disabled]="!modifierToggleEnabled" (ngModelChange)="selectionModel.toggleOperator()" type="radio" class="btn-check" id="logicalOperatorAnd_{{name}}" name="logicalOperatorAnd_{{name}}" value="and">
<label class="btn btn-outline-primary" for="logicalOperatorAnd_{{name}}" i18n>All</label>
<input [(ngModel)]="selectionModel.logicalOperator" [disabled]="!modifierToggleEnabled" (ngModelChange)="selectionModel.toggleOperator()" type="radio" class="btn-check" id="logicalOperatorOr_{{name}}" name="logicalOperatorOr_{{name}}" value="or">
<label class="btn btn-outline-primary" for="logicalOperatorOr_{{name}}" i18n>Any</label>
</div>
</div>
<div *ngIf="!editing && !manyToOne" class="list-group-item d-flex">
<div class="btn-group btn-group-xs flex-fill" role="group">
<input [(ngModel)]="selectionModel.intersection" [disabled]="!modifierToggleEnabled" (ngModelChange)="selectionModel.toggleIntersection()" type="radio" class="btn-check" id="intersectionInclude_{{name}}" name="intersectionInclude_{{name}}" value="include">
<label class="btn btn-outline-primary" for="intersectionInclude_{{name}}" i18n>Include</label>
<input [(ngModel)]="selectionModel.intersection" [disabled]="!modifierToggleEnabled" (ngModelChange)="selectionModel.toggleIntersection()" type="radio" class="btn-check" id="intersectionExclude_{{name}}" name="intersectionExclude_{{name}}" value="exclude">
<label class="btn btn-outline-primary" for="intersectionExclude_{{name}}" i18n>Exclude</label>
</div>
</div>
<div class="list-group-item">
@@ -34,7 +42,7 @@
<use xlink:href="assets/bootstrap-icons.svg#arrow-right" />
</svg>
</button>
<div *ngIf="!editing && multiple" class="list-group-item list-group-item-note pt-1 pb-2">
<div *ngIf="!editing && manyToOne" class="list-group-item list-group-item-note pt-1 pb-2">
<small i18n>Click again to exclude items.</small>
</div>
</div>

View File

@@ -18,12 +18,25 @@ export interface ChangedItems {
itemsToRemove: MatchingModel[]
}
export enum LogicalOperator {
And = 'and',
Or = 'or',
}
export enum Intersection {
Include = 'include',
Exclude = 'exclude',
}
export class FilterableDropdownSelectionModel {
changed = new Subject<FilterableDropdownSelectionModel>()
multiple = false
private _logicalOperator = 'and'
temporaryLogicalOperator = this._logicalOperator
manyToOne = false
singleSelect = false
private _logicalOperator: LogicalOperator = LogicalOperator.And
temporaryLogicalOperator: LogicalOperator = this._logicalOperator
private _intersection: Intersection = Intersection.Include
temporaryIntersection: Intersection = this._intersection
items: MatchingModel[] = []
@@ -86,7 +99,30 @@ export class FilterableDropdownSelectionModel {
(state != ToggleableItemState.Selected &&
state != ToggleableItemState.Excluded)
) {
this.temporarySelectionStates.set(id, ToggleableItemState.Selected)
if (this.manyToOne || this.singleSelect) {
this.temporarySelectionStates.set(id, ToggleableItemState.Selected)
if (this.singleSelect) {
for (let key of this.temporarySelectionStates.keys()) {
if (key != id) {
this.temporarySelectionStates.delete(key)
}
}
}
} else {
let newState =
this.intersection == Intersection.Include
? ToggleableItemState.Selected
: ToggleableItemState.Excluded
if (!id) newState = ToggleableItemState.Selected
if (
state == ToggleableItemState.Excluded &&
this.intersection == Intersection.Exclude
) {
newState = ToggleableItemState.NotSelected
}
this.temporarySelectionStates.set(id, newState)
}
} else if (
state == ToggleableItemState.Selected ||
state == ToggleableItemState.Excluded
@@ -94,14 +130,6 @@ export class FilterableDropdownSelectionModel {
this.temporarySelectionStates.delete(id)
}
if (!this.multiple) {
for (let key of this.temporarySelectionStates.keys()) {
if (key != id) {
this.temporarySelectionStates.delete(key)
}
}
}
if (!id) {
for (let key of this.temporarySelectionStates.keys()) {
if (key) {
@@ -119,19 +147,36 @@ export class FilterableDropdownSelectionModel {
exclude(id: number, fireEvent: boolean = true) {
let state = this.temporarySelectionStates.get(id)
if (state == null || state != ToggleableItemState.Excluded) {
this.temporarySelectionStates.set(id, ToggleableItemState.Excluded)
this.temporaryLogicalOperator = this._logicalOperator = 'and'
} else if (state == ToggleableItemState.Excluded) {
this.temporarySelectionStates.delete(id)
}
if (id && (state == null || state != ToggleableItemState.Excluded)) {
this.temporaryLogicalOperator = this._logicalOperator = this.manyToOne
? LogicalOperator.And
: LogicalOperator.Or
if (!this.multiple) {
for (let key of this.temporarySelectionStates.keys()) {
if (key != id) {
this.temporarySelectionStates.delete(key)
if (this.manyToOne || this.singleSelect) {
this.temporarySelectionStates.set(id, ToggleableItemState.Excluded)
if (this.singleSelect) {
for (let key of this.temporarySelectionStates.keys()) {
if (key != id) {
this.temporarySelectionStates.delete(key)
}
}
}
} else {
let newState =
this.intersection == Intersection.Include
? ToggleableItemState.Selected
: ToggleableItemState.Excluded
if (
state == ToggleableItemState.Selected &&
this.intersection == Intersection.Include
) {
newState = ToggleableItemState.NotSelected
}
this.temporarySelectionStates.set(id, newState)
}
} else if (!id || state == ToggleableItemState.Excluded) {
this.temporarySelectionStates.delete(id)
}
if (fireEvent) {
@@ -143,11 +188,11 @@ export class FilterableDropdownSelectionModel {
return this.selectionStates.get(id) || ToggleableItemState.NotSelected
}
get logicalOperator(): string {
get logicalOperator(): LogicalOperator {
return this.temporaryLogicalOperator
}
set logicalOperator(operator: string) {
set logicalOperator(operator: LogicalOperator) {
this.temporaryLogicalOperator = operator
}
@@ -155,6 +200,26 @@ export class FilterableDropdownSelectionModel {
this.changed.next(this)
}
get intersection(): Intersection {
return this.temporaryIntersection
}
set intersection(intersection: Intersection) {
this.temporaryIntersection = intersection
}
toggleIntersection() {
if (this.temporarySelectionStates.size === 0) return
let newState =
this.intersection == Intersection.Include
? ToggleableItemState.Selected
: ToggleableItemState.Excluded
this.temporarySelectionStates.forEach((state, key) => {
this.temporarySelectionStates.set(key, newState)
})
this.changed.next(this)
}
get(id: number) {
return (
this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected
@@ -171,7 +236,8 @@ export class FilterableDropdownSelectionModel {
clear(fireEvent = true) {
this.temporarySelectionStates.clear()
this.temporaryLogicalOperator = this._logicalOperator = 'and'
this.temporaryLogicalOperator = this._logicalOperator = LogicalOperator.And
this.temporaryIntersection = this._intersection = Intersection.Include
if (fireEvent) {
this.changed.next(this)
}
@@ -194,6 +260,8 @@ export class FilterableDropdownSelectionModel {
return true
} else if (this.temporaryLogicalOperator !== this._logicalOperator) {
return true
} else if (this.temporaryIntersection !== this._intersection) {
return true
} else {
return false
}
@@ -217,13 +285,18 @@ export class FilterableDropdownSelectionModel {
this.selectionStates.set(key, value)
})
this._logicalOperator = this.temporaryLogicalOperator
this._intersection = this.temporaryIntersection
}
reset() {
reset(complete: boolean = false) {
this.temporarySelectionStates.clear()
this.selectionStates.forEach((value, key) => {
this.temporarySelectionStates.set(key, value)
})
if (complete) {
this.selectionStates.clear()
} else {
this.selectionStates.forEach((value, key) => {
this.temporarySelectionStates.set(key, value)
})
}
}
diff(): ChangedItems {
@@ -269,14 +342,16 @@ export class FilterableDropdownComponent {
return this._selectionModel.items
}
_selectionModel = new FilterableDropdownSelectionModel()
_selectionModel: FilterableDropdownSelectionModel =
new FilterableDropdownSelectionModel()
@Input()
set selectionModel(model: FilterableDropdownSelectionModel) {
if (this.selectionModel) {
this.selectionModel.changed.complete()
model.items = this.selectionModel.items
model.multiple = this.selectionModel.multiple
model.manyToOne = this.selectionModel.manyToOne
model.singleSelect = this.editing && !this.selectionModel.manyToOne
}
model.changed.subscribe((updatedModel) => {
this.selectionModelChange.next(updatedModel)
@@ -292,12 +367,12 @@ export class FilterableDropdownComponent {
selectionModelChange = new EventEmitter<FilterableDropdownSelectionModel>()
@Input()
set multiple(value: boolean) {
this.selectionModel.multiple = value
set manyToOne(manyToOne: boolean) {
this.selectionModel.manyToOne = manyToOne
}
get multiple() {
return this.selectionModel.multiple
get manyToOne() {
return this.selectionModel.manyToOne
}
@Input()
@@ -327,16 +402,20 @@ export class FilterableDropdownComponent {
@Output()
opened = new EventEmitter()
get operatorToggleEnabled(): boolean {
return (
this.selectionModel.selectionSize() > 1 &&
this.selectionModel.getExcludedItems().length == 0
)
get modifierToggleEnabled(): boolean {
return this.manyToOne
? this.selectionModel.selectionSize() > 1 &&
this.selectionModel.getExcludedItems().length == 0
: !this.selectionModel.isNoneSelected()
}
@Input()
documentCounts: SelectionDataItem[]
get name(): string {
return this.title ? this.title.replace(/\s/g, '_').toLowerCase() : null
}
getUpdatedDocumentCount(id: number) {
if (this.documentCounts) {
return this.documentCounts.find((c) => c.id === id)?.document_count
@@ -346,7 +425,6 @@ export class FilterableDropdownComponent {
modelIsDirty: boolean = false
constructor(private filterPipe: FilterPipe) {
this.selectionModel = new FilterableDropdownSelectionModel()
this.selectionModelChange.subscribe((updatedModel) => {
this.modelIsDirty = updatedModel.isDirty()
})
@@ -400,7 +478,7 @@ export class FilterableDropdownComponent {
}
reset() {
this.selectionModel.reset()
this.selectionModel.reset(true)
this.selectionModelChange.emit(this.selectionModel)
}
}

View File

@@ -30,7 +30,7 @@
[items]="tags"
[disabled]="!userCanEditAll"
[editing]="true"
[multiple]="true"
[manyToOne]="true"
[applyOnClose]="applyOnClose"
(opened)="openTagsDropdown()"
[(selectionModel)]="tagSelectionModel"

View File

@@ -14,19 +14,19 @@
</div>
</div>
<div class="btn-group flex-fill" role="group">
<input type="radio" class="btn-check" [(ngModel)]="displayMode" value="details" (ngModelChange)="saveDisplayMode()" id="displayModeDetails">
<input type="radio" class="btn-check" [(ngModel)]="displayMode" value="details" (ngModelChange)="saveDisplayMode()" id="displayModeDetails" name="displayModeDetails">
<label for="displayModeDetails" class="btn btn-outline-primary btn-sm">
<svg class="toolbaricon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#list-ul" />
</svg>
</label>
<input type="radio" class="btn-check" [(ngModel)]="displayMode" value="smallCards" (ngModelChange)="saveDisplayMode()" id="displayModeSmall">
<input type="radio" class="btn-check" [(ngModel)]="displayMode" value="smallCards" (ngModelChange)="saveDisplayMode()" id="displayModeSmall" name="displayModeSmall">
<label for="displayModeSmall" class="btn btn-outline-primary btn-sm">
<svg class="toolbaricon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#grid" />
</svg>
</label>
<input type="radio" class="btn-check" [(ngModel)]="displayMode" value="largeCards" (ngModelChange)="saveDisplayMode()" id="displayModeLarge">
<input type="radio" class="btn-check" [(ngModel)]="displayMode" value="largeCards" (ngModelChange)="saveDisplayMode()" id="displayModeLarge" name="displayModeLarge">
<label for="displayModeLarge" class="btn btn-outline-primary btn-sm">
<svg class="toolbaricon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#hdd-stack" />

View File

@@ -27,7 +27,7 @@
<app-filterable-dropdown class="flex-fill" title="Tags" icon="tag-fill" i18n-title
filterPlaceholder="Filter tags" i18n-filterPlaceholder
[items]="tags"
[multiple]="true"
[manyToOne]="true"
[(selectionModel)]="tagSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onTagsDropdownOpen()"

View File

@@ -21,10 +21,10 @@ import {
FILTER_ADDED_AFTER,
FILTER_ADDED_BEFORE,
FILTER_ASN,
FILTER_CORRESPONDENT,
FILTER_HAS_CORRESPONDENT_ANY,
FILTER_CREATED_AFTER,
FILTER_CREATED_BEFORE,
FILTER_DOCUMENT_TYPE,
FILTER_HAS_DOCUMENT_TYPE_ANY,
FILTER_FULLTEXT_MORELIKE,
FILTER_FULLTEXT_QUERY,
FILTER_HAS_ANY_TAG,
@@ -33,12 +33,22 @@ import {
FILTER_DOES_NOT_HAVE_TAG,
FILTER_TITLE,
FILTER_TITLE_CONTENT,
FILTER_STORAGE_PATH,
FILTER_HAS_STORAGE_PATH_ANY,
FILTER_ASN_ISNULL,
FILTER_ASN_GT,
FILTER_ASN_LT,
FILTER_DOES_NOT_HAVE_CORRESPONDENT,
FILTER_DOES_NOT_HAVE_DOCUMENT_TYPE,
FILTER_DOES_NOT_HAVE_STORAGE_PATH,
FILTER_DOCUMENT_TYPE,
FILTER_CORRESPONDENT,
FILTER_STORAGE_PATH,
} from 'src/app/data/filter-rule-type'
import { FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component'
import {
FilterableDropdownSelectionModel,
Intersection,
LogicalOperator,
} from '../../common/filterable-dropdown/filterable-dropdown.component'
import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'
import {
DocumentService,
@@ -93,7 +103,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
if (this.filterRules.length == 1) {
let rule = this.filterRules[0]
switch (this.filterRules[0].rule_type) {
case FILTER_CORRESPONDENT:
case FILTER_HAS_CORRESPONDENT_ANY:
if (rule.value) {
return $localize`Correspondent: ${
this.correspondents.find((c) => c.id == +rule.value)?.name
@@ -102,7 +112,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
return $localize`Without correspondent`
}
case FILTER_DOCUMENT_TYPE:
case FILTER_HAS_DOCUMENT_TYPE_ANY:
if (rule.value) {
return $localize`Type: ${
this.documentTypes.find((dt) => dt.id == +rule.value)?.name
@@ -335,6 +345,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
this.dateAddedBefore = rule.value
break
case FILTER_HAS_TAGS_ALL:
this.tagSelectionModel.logicalOperator = LogicalOperator.And
this.tagSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Selected,
@@ -342,7 +353,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
)
break
case FILTER_HAS_TAGS_ANY:
this.tagSelectionModel.logicalOperator = 'or'
this.tagSelectionModel.logicalOperator = LogicalOperator.Or
this.tagSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Selected,
@@ -360,26 +371,59 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
)
break
case FILTER_CORRESPONDENT:
case FILTER_HAS_CORRESPONDENT_ANY:
this.correspondentSelectionModel.logicalOperator = LogicalOperator.Or
this.correspondentSelectionModel.intersection = Intersection.Include
this.correspondentSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Selected,
false
)
break
case FILTER_DOES_NOT_HAVE_CORRESPONDENT:
this.correspondentSelectionModel.intersection = Intersection.Exclude
this.correspondentSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Excluded,
false
)
break
case FILTER_DOCUMENT_TYPE:
case FILTER_HAS_DOCUMENT_TYPE_ANY:
this.documentTypeSelectionModel.logicalOperator = LogicalOperator.Or
this.documentTypeSelectionModel.intersection = Intersection.Include
this.documentTypeSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Selected,
false
)
break
case FILTER_DOES_NOT_HAVE_DOCUMENT_TYPE:
this.documentTypeSelectionModel.intersection = Intersection.Exclude
this.documentTypeSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Excluded,
false
)
break
case FILTER_STORAGE_PATH:
case FILTER_HAS_STORAGE_PATH_ANY:
this.storagePathSelectionModel.logicalOperator = LogicalOperator.Or
this.storagePathSelectionModel.intersection = Intersection.Include
this.storagePathSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Selected,
false
)
break
case FILTER_DOES_NOT_HAVE_STORAGE_PATH:
this.storagePathSelectionModel.intersection = Intersection.Exclude
this.storagePathSelectionModel.set(
rule.value ? +rule.value : null,
ToggleableItemState.Excluded,
false
)
break
case FILTER_ASN_ISNULL:
this.textFilterTarget = TEXT_FILTER_TARGET_ASN
this.textFilterModifier =
@@ -469,7 +513,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
filterRules.push({ rule_type: FILTER_HAS_ANY_TAG, value: 'false' })
} else {
const tagFilterType =
this.tagSelectionModel.logicalOperator == 'and'
this.tagSelectionModel.logicalOperator == LogicalOperator.And
? FILTER_HAS_TAGS_ALL
: FILTER_HAS_TAGS_ANY
this.tagSelectionModel
@@ -491,28 +535,66 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
})
})
}
this.correspondentSelectionModel
.getSelectedItems()
.forEach((correspondent) => {
filterRules.push({
rule_type: FILTER_CORRESPONDENT,
value: correspondent.id?.toString(),
if (this.correspondentSelectionModel.isNoneSelected()) {
filterRules.push({ rule_type: FILTER_CORRESPONDENT, value: null })
} else {
this.correspondentSelectionModel
.getSelectedItems()
.forEach((correspondent) => {
filterRules.push({
rule_type: FILTER_HAS_CORRESPONDENT_ANY,
value: correspondent.id?.toString(),
})
})
})
this.documentTypeSelectionModel
.getSelectedItems()
.forEach((documentType) => {
filterRules.push({
rule_type: FILTER_DOCUMENT_TYPE,
value: documentType.id?.toString(),
this.correspondentSelectionModel
.getExcludedItems()
.forEach((correspondent) => {
filterRules.push({
rule_type: FILTER_DOES_NOT_HAVE_CORRESPONDENT,
value: correspondent.id?.toString(),
})
})
})
this.storagePathSelectionModel.getSelectedItems().forEach((storagePath) => {
filterRules.push({
rule_type: FILTER_STORAGE_PATH,
value: storagePath.id?.toString(),
})
})
}
if (this.documentTypeSelectionModel.isNoneSelected()) {
filterRules.push({ rule_type: FILTER_DOCUMENT_TYPE, value: null })
} else {
this.documentTypeSelectionModel
.getSelectedItems()
.forEach((documentType) => {
filterRules.push({
rule_type: FILTER_HAS_DOCUMENT_TYPE_ANY,
value: documentType.id?.toString(),
})
})
this.documentTypeSelectionModel
.getExcludedItems()
.forEach((documentType) => {
filterRules.push({
rule_type: FILTER_DOES_NOT_HAVE_DOCUMENT_TYPE,
value: documentType.id?.toString(),
})
})
}
if (this.storagePathSelectionModel.isNoneSelected()) {
filterRules.push({ rule_type: FILTER_STORAGE_PATH, value: null })
} else {
this.storagePathSelectionModel
.getSelectedItems()
.forEach((storagePath) => {
filterRules.push({
rule_type: FILTER_HAS_STORAGE_PATH_ANY,
value: storagePath.id?.toString(),
})
})
this.storagePathSelectionModel
.getExcludedItems()
.forEach((storagePath) => {
filterRules.push({
rule_type: FILTER_DOES_NOT_HAVE_STORAGE_PATH,
value: storagePath.id?.toString(),
})
})
}
if (this.dateCreatedBefore) {
filterRules.push({
rule_type: FILTER_CREATED_BEFORE,

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { FILTER_CORRESPONDENT } from 'src/app/data/filter-rule-type'
import { FILTER_HAS_CORRESPONDENT_ANY } from 'src/app/data/filter-rule-type'
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
@@ -35,7 +35,7 @@ export class CorrespondentListComponent extends ManagementListComponent<Paperles
toastService,
documentListViewService,
permissionsService,
FILTER_CORRESPONDENT,
FILTER_HAS_CORRESPONDENT_ANY,
$localize`correspondent`,
$localize`correspondents`,
PermissionType.Correspondent,

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { FILTER_DOCUMENT_TYPE } from 'src/app/data/filter-rule-type'
import { FILTER_HAS_DOCUMENT_TYPE_ANY } from 'src/app/data/filter-rule-type'
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
import {
@@ -32,7 +32,7 @@ export class DocumentTypeListComponent extends ManagementListComponent<Paperless
toastService,
documentListViewService,
permissionsService,
FILTER_DOCUMENT_TYPE,
FILTER_HAS_DOCUMENT_TYPE_ANY,
$localize`document type`,
$localize`document types`,
PermissionType.DocumentType,

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { FILTER_STORAGE_PATH } from 'src/app/data/filter-rule-type'
import { FILTER_HAS_STORAGE_PATH_ANY } from 'src/app/data/filter-rule-type'
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
import {
@@ -32,7 +32,7 @@ export class StoragePathListComponent extends ManagementListComponent<PaperlessS
toastService,
documentListViewService,
permissionsService,
FILTER_STORAGE_PATH,
FILTER_HAS_STORAGE_PATH_ANY,
$localize`storage path`,
$localize`storage paths`,
PermissionType.StoragePath,

View File

@@ -8,8 +8,12 @@ export const FILTER_ASN_GT = 23
export const FILTER_ASN_LT = 24
export const FILTER_CORRESPONDENT = 3
export const FILTER_HAS_CORRESPONDENT_ANY = 26
export const FILTER_DOES_NOT_HAVE_CORRESPONDENT = 27
export const FILTER_DOCUMENT_TYPE = 4
export const FILTER_HAS_DOCUMENT_TYPE_ANY = 28
export const FILTER_DOES_NOT_HAVE_DOCUMENT_TYPE = 29
export const FILTER_IS_IN_INBOX = 5
export const FILTER_HAS_TAGS_ALL = 6
@@ -18,6 +22,8 @@ export const FILTER_DOES_NOT_HAVE_TAG = 17
export const FILTER_HAS_TAGS_ANY = 22
export const FILTER_STORAGE_PATH = 25
export const FILTER_HAS_STORAGE_PATH_ANY = 30
export const FILTER_DOES_NOT_HAVE_STORAGE_PATH = 31
export const FILTER_CREATED_BEFORE = 8
export const FILTER_CREATED_AFTER = 9
@@ -63,6 +69,18 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
datatype: 'correspondent',
multi: false,
},
{
id: FILTER_HAS_CORRESPONDENT_ANY,
filtervar: 'correspondent__id__in',
datatype: 'correspondent',
multi: true,
},
{
id: FILTER_DOES_NOT_HAVE_CORRESPONDENT,
filtervar: 'correspondent__id__none',
datatype: 'correspondent',
multi: true,
},
{
id: FILTER_STORAGE_PATH,
filtervar: 'storage_path__id',
@@ -70,6 +88,18 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
datatype: 'storage_path',
multi: false,
},
{
id: FILTER_HAS_STORAGE_PATH_ANY,
filtervar: 'storage_path__id__in',
datatype: 'storage_path',
multi: true,
},
{
id: FILTER_DOES_NOT_HAVE_STORAGE_PATH,
filtervar: 'storage_path__id__none',
datatype: 'storage_path',
multi: true,
},
{
id: FILTER_DOCUMENT_TYPE,
filtervar: 'document_type__id',
@@ -77,6 +107,18 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
datatype: 'document_type',
multi: false,
},
{
id: FILTER_HAS_DOCUMENT_TYPE_ANY,
filtervar: 'document_type__id__in',
datatype: 'document_type',
multi: true,
},
{
id: FILTER_DOES_NOT_HAVE_DOCUMENT_TYPE,
filtervar: 'document_type__id__none',
datatype: 'document_type',
multi: true,
},
{
id: FILTER_IS_IN_INBOX,
filtervar: 'is_in_inbox',

View File

@@ -86,12 +86,12 @@ export function queryParamsFromFilterRules(filterRules: FilterRule[]): Params {
let params = {}
for (let rule of filterRules) {
let ruleType = FILTER_RULE_TYPES.find((t) => t.id == rule.rule_type)
if (ruleType.multi) {
if (ruleType.isnull_filtervar && rule.value == null) {
params[ruleType.isnull_filtervar] = 1
} else if (ruleType.multi) {
params[ruleType.filtervar] = params[ruleType.filtervar]
? params[ruleType.filtervar] + ',' + rule.value
: rule.value
} else if (ruleType.isnull_filtervar && rule.value == null) {
params[ruleType.isnull_filtervar] = 1
} else {
params[ruleType.filtervar] = rule.value
if (ruleType.datatype == 'boolean')