mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-11-14 01:55:25 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13ffed0702 | ||
|
|
b42bf50b7e | ||
|
|
d31110278b | ||
|
|
5d98a5e5c8 | ||
|
|
fc8c4e91ec | ||
|
|
e746e008a0 | ||
|
|
897f6a9e5a |
No files matched your search
+4
-3
@@ -587,9 +587,10 @@ documents from the web UI:
|
||||
- From the document list, select one or more documents and choose **Run workflow** from the "Actions" menu.
|
||||
- From an individual document, choose **Run workflow** from the "Actions" menu.
|
||||
|
||||
You will be asked which workflow to run. By default the workflow's trigger filters still apply, so documents that do
|
||||
not match are skipped. You can instead choose to **run on all selected documents**, which ignores the trigger filters
|
||||
and runs the workflow's actions on every selected document.
|
||||
You will be asked which workflow to run. From the document list, the workflow's trigger filters apply by default, so
|
||||
documents that do not match are skipped. You can choose to **run on all selected documents** to ignore the filters.
|
||||
From an individual document, the option to ignore trigger filters is selected by default. Clear it to run the workflow
|
||||
only if the document matches its trigger filters.
|
||||
|
||||
Manual runs happen in the background. As with scheduled workflows, the document list is not refreshed automatically when
|
||||
they finish, so you may need to reload the list to see the results.
|
||||
|
||||
+101
-80
@@ -1366,7 +1366,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">1971</context>
|
||||
<context context-type="linenumber">1973</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="1577733187050997705" datatype="html">
|
||||
@@ -3420,23 +3420,23 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">1972</context>
|
||||
<context context-type="linenumber">1974</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1019</context>
|
||||
<context context-type="linenumber">1034</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1058</context>
|
||||
<context context-type="linenumber">1073</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1081</context>
|
||||
<context context-type="linenumber">1096</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1117</context>
|
||||
<context context-type="linenumber">1132</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/manage/document-attributes/custom-fields/custom-fields.component.ts</context>
|
||||
@@ -4199,27 +4199,27 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">637</context>
|
||||
<context context-type="linenumber">652</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">677</context>
|
||||
<context context-type="linenumber">692</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">715</context>
|
||||
<context context-type="linenumber">730</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">753</context>
|
||||
<context context-type="linenumber">768</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">815</context>
|
||||
<context context-type="linenumber">830</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">953</context>
|
||||
<context context-type="linenumber">968</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6088768251338567957" datatype="html">
|
||||
@@ -4339,7 +4339,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2025</context>
|
||||
<context context-type="linenumber">2027</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6661109599266152398" datatype="html">
|
||||
@@ -4350,7 +4350,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2026</context>
|
||||
<context context-type="linenumber">2028</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5162686434580248853" datatype="html">
|
||||
@@ -4361,7 +4361,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2027</context>
|
||||
<context context-type="linenumber">2029</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6665634854532231106" datatype="html">
|
||||
@@ -4413,18 +4413,32 @@
|
||||
<context context-type="linenumber">13,14</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="261810320774538615" datatype="html">
|
||||
<source>Run on this document regardless of trigger filters</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/common/confirm-dialog/run-workflow-confirm-dialog/run-workflow-confirm-dialog.component.html</context>
|
||||
<context context-type="linenumber">22,23</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2322522720854680528" datatype="html">
|
||||
<source>Ignore the workflow's trigger filters for this document.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/common/confirm-dialog/run-workflow-confirm-dialog/run-workflow-confirm-dialog.component.html</context>
|
||||
<context context-type="linenumber">23,24</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4512110365422311821" datatype="html">
|
||||
<source>Run on all selected documents</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/common/confirm-dialog/run-workflow-confirm-dialog/run-workflow-confirm-dialog.component.html</context>
|
||||
<context context-type="linenumber">21,22</context>
|
||||
<context context-type="linenumber">25,26</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6575910678008555513" datatype="html">
|
||||
<source>Ignore the workflow's trigger filters and run on every selected document.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/common/confirm-dialog/run-workflow-confirm-dialog/run-workflow-confirm-dialog.component.html</context>
|
||||
<context context-type="linenumber">22,23</context>
|
||||
<context context-type="linenumber">26,27</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2509141182388535183" datatype="html">
|
||||
@@ -6654,7 +6668,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">957</context>
|
||||
<context context-type="linenumber">972</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="1616074213645042277" datatype="html">
|
||||
@@ -8431,7 +8445,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">582</context>
|
||||
<context context-type="linenumber">597</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">this string is used to separate processing, failed and added on the file upload widget</note>
|
||||
</trans-unit>
|
||||
@@ -8760,7 +8774,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">318</context>
|
||||
<context context-type="linenumber">320</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7049887240439736400" datatype="html">
|
||||
@@ -9247,7 +9261,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">955</context>
|
||||
<context context-type="linenumber">970</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5992101894268263750" datatype="html">
|
||||
@@ -9272,7 +9286,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1015</context>
|
||||
<context context-type="linenumber">1030</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2951161989614003846" datatype="html">
|
||||
@@ -9304,7 +9318,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">1607</context>
|
||||
<context context-type="linenumber">1609</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="838042392151392247" datatype="html">
|
||||
@@ -9322,88 +9336,88 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">320</context>
|
||||
<context context-type="linenumber">322</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="523213570140181690" datatype="html">
|
||||
<source>Workflow will run on "<x id="PH" equiv-text="this.document().title"/>" in the background.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">1600</context>
|
||||
<context context-type="linenumber">1602</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6030453331794586802" datatype="html">
|
||||
<source>Error downloading document</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">1671</context>
|
||||
<context context-type="linenumber">1673</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4458954481601077369" datatype="html">
|
||||
<source>Page Fit</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">1749</context>
|
||||
<context context-type="linenumber">1751</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4663705961777238777" datatype="html">
|
||||
<source>PDF edit operation for "<x id="PH" equiv-text="this.document().title"/>" will begin in the background.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">1992</context>
|
||||
<context context-type="linenumber">1994</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="9043972994040261999" datatype="html">
|
||||
<source>Error executing PDF edit operation</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2004</context>
|
||||
<context context-type="linenumber">2006</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6172690334763056188" datatype="html">
|
||||
<source>Please enter the current password before attempting to remove it.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2015</context>
|
||||
<context context-type="linenumber">2017</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="968660764814228922" datatype="html">
|
||||
<source>Password removal operation for "<x id="PH" equiv-text="this.document().title"/>" will begin in the background.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2049</context>
|
||||
<context context-type="linenumber">2051</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2282118435712883014" datatype="html">
|
||||
<source>Error executing password removal operation</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2063</context>
|
||||
<context context-type="linenumber">2065</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3740891324955700797" datatype="html">
|
||||
<source>Print failed.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2113</context>
|
||||
<context context-type="linenumber">2115</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6457245677384603573" datatype="html">
|
||||
<source>Error loading document for printing.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2122</context>
|
||||
<context context-type="linenumber">2124</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6085793215710522488" datatype="html">
|
||||
<source>An error occurred loading tiff: <x id="PH" equiv-text="err.toString()"/></source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
|
||||
<context context-type="linenumber">2205</context>
|
||||
<context context-type="linenumber">2207</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">2211</context>
|
||||
<context context-type="linenumber">2213</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4958946940233632319" datatype="html">
|
||||
@@ -9687,7 +9701,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1115</context>
|
||||
<context context-type="linenumber">1130</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7251533806673754434" datatype="html">
|
||||
@@ -9722,46 +9736,53 @@
|
||||
<source>Run a workflow on <x id="PH" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">319</context>
|
||||
<context context-type="linenumber">321</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8161885405686762788" datatype="html">
|
||||
<source>Workflow will run on the selected documents in the background.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">339</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3401633333450192408" datatype="html">
|
||||
<source>Bulk operation queued.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">358</context>
|
||||
<context context-type="linenumber">373</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5709555629190115111" datatype="html">
|
||||
<source>View task</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">362</context>
|
||||
<context context-type="linenumber">377</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="1215215387232313677" datatype="html">
|
||||
<source>Error executing bulk operation</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">414</context>
|
||||
<context context-type="linenumber">429</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7894972847287473517" datatype="html">
|
||||
<source>"<x id="PH" equiv-text="items[0].name"/>"</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">574</context>
|
||||
<context context-type="linenumber">589</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">580</context>
|
||||
<context context-type="linenumber">595</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8639884465898458690" datatype="html">
|
||||
<source>"<x id="PH" equiv-text="items[0].name"/>" and "<x id="PH_1" equiv-text="items[1].name"/>"</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">576</context>
|
||||
<context context-type="linenumber">591</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">This is for messages like 'modify "tag1" and "tag2"'</note>
|
||||
</trans-unit>
|
||||
@@ -9769,7 +9790,7 @@
|
||||
<source><x id="PH" equiv-text="list"/> and "<x id="PH_1" equiv-text="items[items.length - 1].name"/>"</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">584,586</context>
|
||||
<context context-type="linenumber">599,601</context>
|
||||
</context-group>
|
||||
<note priority="1" from="description">this is for messages like 'modify "tag1", "tag2" and "tag3"'</note>
|
||||
</trans-unit>
|
||||
@@ -9777,14 +9798,14 @@
|
||||
<source>Confirm tags assignment</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">601</context>
|
||||
<context context-type="linenumber">616</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6619516195038467207" datatype="html">
|
||||
<source>This operation will add the tag "<x id="PH" equiv-text="tag.name"/>" to <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">607</context>
|
||||
<context context-type="linenumber">622</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="1894412783609570695" datatype="html">
|
||||
@@ -9793,14 +9814,14 @@
|
||||
)"/> to <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">612,614</context>
|
||||
<context context-type="linenumber">627,629</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7181166515756808573" datatype="html">
|
||||
<source>This operation will remove the tag "<x id="PH" equiv-text="tag.name"/>" from <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">620</context>
|
||||
<context context-type="linenumber">635</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3819792277998068944" datatype="html">
|
||||
@@ -9809,7 +9830,7 @@
|
||||
)"/> from <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">625,627</context>
|
||||
<context context-type="linenumber">640,642</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2739066218579571288" datatype="html">
|
||||
@@ -9820,84 +9841,84 @@
|
||||
)"/> on <x id="PH_2" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">629,633</context>
|
||||
<context context-type="linenumber">644,648</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2996713129519325161" datatype="html">
|
||||
<source>Confirm correspondent assignment</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">670</context>
|
||||
<context context-type="linenumber">685</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6900893559485781849" datatype="html">
|
||||
<source>This operation will assign the correspondent "<x id="PH" equiv-text="correspondent.name"/>" to <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">672</context>
|
||||
<context context-type="linenumber">687</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="1257522660364398440" datatype="html">
|
||||
<source>This operation will remove the correspondent from <x id="PH" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">674</context>
|
||||
<context context-type="linenumber">689</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5393409374423140648" datatype="html">
|
||||
<source>Confirm document type assignment</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">708</context>
|
||||
<context context-type="linenumber">723</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="332180123895325027" datatype="html">
|
||||
<source>This operation will assign the document type "<x id="PH" equiv-text="documentType.name"/>" to <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">710</context>
|
||||
<context context-type="linenumber">725</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2236642492594872779" datatype="html">
|
||||
<source>This operation will remove the document type from <x id="PH" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">712</context>
|
||||
<context context-type="linenumber">727</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6386555513013840736" datatype="html">
|
||||
<source>Confirm storage path assignment</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">746</context>
|
||||
<context context-type="linenumber">761</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8750527458618415924" datatype="html">
|
||||
<source>This operation will assign the storage path "<x id="PH" equiv-text="storagePath.name"/>" to <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">748</context>
|
||||
<context context-type="linenumber">763</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="60728365335056946" datatype="html">
|
||||
<source>This operation will remove the storage path from <x id="PH" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">750</context>
|
||||
<context context-type="linenumber">765</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4187352575310415704" datatype="html">
|
||||
<source>Confirm custom field assignment</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">779</context>
|
||||
<context context-type="linenumber">794</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7966494636326273856" datatype="html">
|
||||
<source>This operation will assign the custom field "<x id="PH" equiv-text="customField.name"/>" to <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">785</context>
|
||||
<context context-type="linenumber">800</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5789455969634598553" datatype="html">
|
||||
@@ -9906,14 +9927,14 @@
|
||||
)"/> to <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">790,792</context>
|
||||
<context context-type="linenumber">805,807</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5648572354333199245" datatype="html">
|
||||
<source>This operation will remove the custom field "<x id="PH" equiv-text="customField.name"/>" from <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">798</context>
|
||||
<context context-type="linenumber">813</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6666899594015948817" datatype="html">
|
||||
@@ -9922,7 +9943,7 @@
|
||||
)"/> from <x id="PH_1" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">803,805</context>
|
||||
<context context-type="linenumber">818,820</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8050047262594964176" datatype="html">
|
||||
@@ -9933,105 +9954,105 @@
|
||||
)"/> on <x id="PH_2" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">807,811</context>
|
||||
<context context-type="linenumber">822,826</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8615059324209654051" datatype="html">
|
||||
<source>Move <x id="PH" equiv-text="this.getSelectionSize()"/> selected document(s) to the trash?</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">954</context>
|
||||
<context context-type="linenumber">969</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="135114644550399974" datatype="html">
|
||||
<source>Moved <x id="PH" equiv-text="count"/> document(s) to the trash</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">981</context>
|
||||
<context context-type="linenumber">996</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8585195717323764335" datatype="html">
|
||||
<source>This operation will permanently recreate the archive files for <x id="PH" equiv-text="this.getSelectionSize()"/> selected document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1016</context>
|
||||
<context context-type="linenumber">1031</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7366623494074776040" datatype="html">
|
||||
<source>The archive files will be re-generated with the current settings.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1017</context>
|
||||
<context context-type="linenumber">1032</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6555329262222566158" datatype="html">
|
||||
<source>Rotate confirm</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1055</context>
|
||||
<context context-type="linenumber">1070</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5203024009814367559" datatype="html">
|
||||
<source>This operation will add rotated versions of the <x id="PH" equiv-text="this.getSelectionSize()"/> document(s).</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1056</context>
|
||||
<context context-type="linenumber">1071</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7910756456450124185" datatype="html">
|
||||
<source>Merge confirm</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1079</context>
|
||||
<context context-type="linenumber">1094</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7643543647233874431" datatype="html">
|
||||
<source>This operation will merge <x id="PH" equiv-text="this.getSelectionSize()"/> selected documents into a new document.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1080</context>
|
||||
<context context-type="linenumber">1095</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7869008840945899895" datatype="html">
|
||||
<source>Merged document will be queued for consumption.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1103</context>
|
||||
<context context-type="linenumber">1118</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="1549333914563613027" datatype="html">
|
||||
<source>The selected documents will become versions of the root document.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1116</context>
|
||||
<context context-type="linenumber">1131</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7099667366799629283" datatype="html">
|
||||
<source>Documents merged as versions.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1131</context>
|
||||
<context context-type="linenumber">1146</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3873496751167944011" datatype="html">
|
||||
<source>Error updating custom fields.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1161</context>
|
||||
<context context-type="linenumber">1176</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6144801143088984138" datatype="html">
|
||||
<source>Share link bundle creation requested.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1209</context>
|
||||
<context context-type="linenumber">1224</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="46019676931295023" datatype="html">
|
||||
<source>Share link bundle creation is not available yet.</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
|
||||
<context context-type="linenumber">1216</context>
|
||||
<context context-type="linenumber">1231</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="6307402210351946694" datatype="html">
|
||||
|
||||
+7
-2
@@ -18,8 +18,13 @@
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="runWorkflowForce" [(ngModel)]="force" />
|
||||
<label class="form-check-label" for="runWorkflowForce" i18n>Run on all selected documents</label>
|
||||
<div class="form-text" i18n>Ignore the workflow's trigger filters and run on every selected document.</div>
|
||||
@if (singleDocument) {
|
||||
<label class="form-check-label" for="runWorkflowForce" i18n>Run on this document regardless of trigger filters</label>
|
||||
<div class="form-text" i18n>Ignore the workflow's trigger filters for this document.</div>
|
||||
} @else {
|
||||
<label class="form-check-label" for="runWorkflowForce" i18n>Run on all selected documents</label>
|
||||
<div class="form-text" i18n>Ignore the workflow's trigger filters and run on every selected document.</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
+21
@@ -39,4 +39,25 @@ describe('RunWorkflowConfirmDialogComponent', () => {
|
||||
expect(options).toHaveLength(2)
|
||||
expect(options[1].textContent).toContain('Manual workflow')
|
||||
})
|
||||
|
||||
it('should describe the checkbox for a selection or a single document', async () => {
|
||||
const checkbox = fixture.nativeElement.querySelector('#runWorkflowForce')
|
||||
expect(checkbox.checked).toBe(false)
|
||||
expect(fixture.nativeElement.textContent).toContain(
|
||||
'Run on all selected documents'
|
||||
)
|
||||
|
||||
component.singleDocument = true
|
||||
component.force = true
|
||||
fixture.detectChanges()
|
||||
await fixture.whenStable()
|
||||
fixture.detectChanges()
|
||||
expect(checkbox.checked).toBe(true)
|
||||
expect(fixture.nativeElement.textContent).toContain(
|
||||
'Run on this document regardless of trigger filters'
|
||||
)
|
||||
expect(fixture.nativeElement.textContent).not.toContain(
|
||||
'Run on all selected documents'
|
||||
)
|
||||
})
|
||||
})
|
||||
+2
@@ -13,6 +13,8 @@ export class RunWorkflowConfirmDialogComponent extends ConfirmDialogComponent {
|
||||
|
||||
public workflowId: number = null
|
||||
|
||||
public singleDocument: boolean = false
|
||||
|
||||
// i.e. ignore the workflow's trigger filters
|
||||
public force: boolean = false
|
||||
|
||||
|
||||
-11
@@ -4,7 +4,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import {
|
||||
NgbDropdown,
|
||||
NgbDropdownModule,
|
||||
NgbModal,
|
||||
NgbModalModule,
|
||||
@@ -251,14 +250,4 @@ describe('CustomFieldsDropdownComponent', () => {
|
||||
expect(createFieldSpy).not.toHaveBeenCalled()
|
||||
expect(addFieldSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should close the dropdown after selecting a filtered field', () => {
|
||||
const dropdown = fixture.debugElement
|
||||
.query(By.directive(NgbDropdown))
|
||||
.injector.get(NgbDropdown)
|
||||
dropdown.open()
|
||||
component.filterText = 'Field 1'
|
||||
component.listFilterEnter()
|
||||
expect(dropdown.isOpen()).toBe(false)
|
||||
})
|
||||
})
|
||||
+1
-7
@@ -11,11 +11,7 @@ import {
|
||||
signal,
|
||||
} from '@angular/core'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import {
|
||||
NgbDropdown,
|
||||
NgbDropdownModule,
|
||||
NgbModal,
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { first, takeUntil } from 'rxjs'
|
||||
import { BootstrapIconComponent } from 'src/app/components/common/bootstrap-icon/bootstrap-icon.component'
|
||||
import { CustomField, DATA_TYPE_LABELS } from 'src/app/data/custom-field'
|
||||
@@ -67,7 +63,6 @@ export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissio
|
||||
created: EventEmitter<CustomField> = new EventEmitter()
|
||||
|
||||
@ViewChild('listFilterTextInput') listFilterTextInput: ElementRef
|
||||
@ViewChild('fieldDropdown') fieldDropdown: NgbDropdown
|
||||
@ViewChildren('button') buttons: QueryList<ElementRef>
|
||||
|
||||
private customFields: CustomField[] = []
|
||||
@@ -125,7 +120,6 @@ export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissio
|
||||
|
||||
addField(field: CustomField) {
|
||||
this.added.emit(field)
|
||||
this.fieldDropdown.close()
|
||||
this.updateUnusedFields()
|
||||
}
|
||||
|
||||
|
||||
@@ -1038,9 +1038,10 @@ describe('DocumentDetailComponent', () => {
|
||||
modalService.activeInstances.subscribe((modal) => (openModal = modal[0]))
|
||||
const toastSpy = jest.spyOn(toastService, 'showInfo')
|
||||
component.runWorkflow()
|
||||
expect(openModal.componentInstance.singleDocument).toBe(true)
|
||||
expect(openModal.componentInstance.force).toBe(true)
|
||||
const modalCloseSpy = jest.spyOn(openModal, 'close')
|
||||
openModal.componentInstance.workflowId = 5
|
||||
openModal.componentInstance.force = true
|
||||
openModal.componentInstance.confirmClicked.next()
|
||||
expect(bulkEditSpy).toHaveBeenCalledWith(
|
||||
{ documents: [doc.id] },
|
||||
@@ -1051,6 +1052,23 @@ describe('DocumentDetailComponent', () => {
|
||||
expect(modalCloseSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should apply workflow filters when the single-document checkbox is cleared', () => {
|
||||
initNormally()
|
||||
const bulkEditSpy = jest.spyOn(documentService, 'bulkEdit')
|
||||
bulkEditSpy.mockReturnValue(of(true))
|
||||
let openModal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((modal) => (openModal = modal[0]))
|
||||
component.runWorkflow()
|
||||
openModal.componentInstance.workflowId = 5
|
||||
openModal.componentInstance.force = false
|
||||
openModal.componentInstance.confirmClicked.next()
|
||||
expect(bulkEditSpy).toHaveBeenCalledWith(
|
||||
{ documents: [doc.id] },
|
||||
'run_workflow',
|
||||
{ workflow: 5, filter_documents: true }
|
||||
)
|
||||
})
|
||||
|
||||
it('should pass remote OCR choice when reprocessing', () => {
|
||||
initNormally()
|
||||
const reprocessSpy = jest.spyOn(documentService, 'reprocessDocuments')
|
||||
|
||||
@@ -1587,6 +1587,8 @@ export class DocumentDetailComponent
|
||||
modal.componentInstance.message = $localize`Run a workflow on "${this.document().title}".`
|
||||
modal.componentInstance.btnCaption = $localize`Run`
|
||||
modal.componentInstance.workflows = this.manualWorkflows()
|
||||
modal.componentInstance.singleDocument = true
|
||||
modal.componentInstance.force = true
|
||||
modal.componentInstance.confirmClicked.subscribe(() => {
|
||||
modal.componentInstance.buttonsEnabled.set(false)
|
||||
this.documentsService
|
||||
|
||||
@@ -686,6 +686,8 @@ describe('BulkEditorComponent', () => {
|
||||
})
|
||||
|
||||
it('should run a workflow on the selection via the run workflow dialog', () => {
|
||||
const toast = jest.spyOn(toastService, 'show')
|
||||
const infoToast = jest.spyOn(toastService, 'showInfo')
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
@@ -699,6 +701,8 @@ describe('BulkEditorComponent', () => {
|
||||
component.runWorkflowSelected()
|
||||
expect(modal).not.toBeUndefined()
|
||||
expect(modal.componentInstance.workflows).toEqual(component.manualWorkflows)
|
||||
expect(modal.componentInstance.singleDocument).toBe(false)
|
||||
expect(modal.componentInstance.force).toBe(false)
|
||||
modal.componentInstance.workflowId = 5
|
||||
modal.componentInstance.force = true
|
||||
modal.componentInstance.confirm()
|
||||
@@ -710,7 +714,12 @@ describe('BulkEditorComponent', () => {
|
||||
workflow: 5,
|
||||
filter_documents: false,
|
||||
})
|
||||
req.flush(true)
|
||||
req.flush({ result: 'OK' })
|
||||
expect(infoToast).toHaveBeenCalledWith(
|
||||
'Workflow will run on the selected documents in the background.'
|
||||
)
|
||||
expect(toast.mock.calls.at(-1)[0].actionName).toBeUndefined()
|
||||
expect(documentListViewService.selected.size).toBe(0)
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&include_selection_data=true`
|
||||
) // list reload
|
||||
@@ -719,6 +728,27 @@ describe('BulkEditorComponent', () => {
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should require ownership of selected documents to run a workflow', () => {
|
||||
component.manualWorkflows = [{ id: 5 }] as any
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
const ownsDocument = jest
|
||||
.spyOn(permissionsService, 'currentUserOwnsObject')
|
||||
.mockReturnValue(false)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3]))
|
||||
|
||||
expect(component.canRunWorkflow).toBe(false)
|
||||
ownsDocument.mockReturnValue(true)
|
||||
expect(component.canRunWorkflow).toBe(true)
|
||||
})
|
||||
|
||||
it('should set modal dialog text accordingly for tag edit confirmation', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
|
||||
|
||||
@@ -308,7 +308,9 @@ export class BulkEditorComponent
|
||||
}
|
||||
|
||||
get canRunWorkflow(): boolean {
|
||||
return this.userCanEditAll && this.manualWorkflows.length > 0
|
||||
return (
|
||||
this.userCanEditAll && this.userOwnsAll && this.manualWorkflows.length > 0
|
||||
)
|
||||
}
|
||||
|
||||
runWorkflowSelected() {
|
||||
@@ -322,10 +324,23 @@ export class BulkEditorComponent
|
||||
modal.componentInstance.confirmClicked
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe(() => {
|
||||
this.executeBulkEditMethod(modal, 'run_workflow', {
|
||||
workflow: modal.componentInstance.workflowId,
|
||||
filter_documents: !modal.componentInstance.force,
|
||||
})
|
||||
modal.componentInstance.buttonsEnabled.set(false)
|
||||
this.documentService
|
||||
.bulkEdit(this.getSelectionQuery(), 'run_workflow', {
|
||||
workflow: modal.componentInstance.workflowId,
|
||||
filter_documents: !modal.componentInstance.force,
|
||||
})
|
||||
.pipe(first())
|
||||
.subscribe({
|
||||
next: () => {
|
||||
modal.close()
|
||||
this.list.selectNone()
|
||||
this.toastService.showInfo(
|
||||
$localize`Workflow will run on the selected documents in the background.`
|
||||
)
|
||||
},
|
||||
error: (error) => this.handleOperationError(modal, error),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -789,6 +789,7 @@ def has_document_operation_permissions(
|
||||
bulk_edit.edit_pdf,
|
||||
bulk_edit.merge_as_versions,
|
||||
bulk_edit.remove_password,
|
||||
bulk_edit.run_workflow,
|
||||
]
|
||||
)
|
||||
or (
|
||||
|
||||
@@ -703,11 +703,12 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
|
||||
|
||||
@mock.patch("documents.views.bulk_edit.run_workflow")
|
||||
def test_run_workflow_requires_ownership(self, m) -> None:
|
||||
"""A non-owner without document ownership is forbidden (actions mutate docs)."""
|
||||
"""A non-owner with change permission cannot run mutating workflow actions."""
|
||||
self.setup_mock(m, "run_workflow")
|
||||
user = UserFactory(username="no_perms")
|
||||
user = UserFactory(username="non_owner")
|
||||
grant_all_global(user)
|
||||
doc = DocumentFactory(owner=UserFactory(username="other"))
|
||||
grant_object(user, doc, "change_document")
|
||||
workflow = self._make_manual_workflow()
|
||||
self.client.force_authenticate(user=user)
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
OBFUSCATED_PASSWORD_MASK = "*" * 10
|
||||
|
||||
|
||||
def is_obfuscated_password(value: str) -> bool:
|
||||
"""
|
||||
True if the value is only mask characters (or empty), meaning a client echoed
|
||||
the placeholder back rather than supplying a new secret
|
||||
"""
|
||||
return value.replace("*", "") == ""
|
||||
|
||||
|
||||
class ObfuscatedPasswordField(serializers.CharField):
|
||||
"""
|
||||
Sends a constant mask string instead of the password in the clear
|
||||
"""
|
||||
|
||||
def to_representation(self, value) -> str:
|
||||
return OBFUSCATED_PASSWORD_MASK
|
||||
|
||||
def to_internal_value(self, data):
|
||||
return data
|
||||
@@ -20,18 +20,19 @@ from rest_framework import serializers
|
||||
from rest_framework.authtoken.serializers import AuthTokenSerializer
|
||||
|
||||
from paperless.config import OCR_RESERVED_USER_ARGS
|
||||
from paperless.fields import ObfuscatedPasswordField
|
||||
from paperless.fields import is_obfuscated_password
|
||||
from paperless.models import ApplicationConfiguration
|
||||
from paperless.network import validate_outbound_http_url
|
||||
from paperless.validators import reject_dangerous_svg
|
||||
from paperless.validators import validate_raster_image
|
||||
from paperless_mail.serialisers import ObfuscatedPasswordField
|
||||
|
||||
logger = logging.getLogger("paperless.settings")
|
||||
|
||||
|
||||
class PasswordValidationMixin:
|
||||
def _has_real_password(self, value: str | None) -> bool:
|
||||
return bool(value) and value.replace("*", "") != ""
|
||||
return bool(value) and not is_obfuscated_password(value)
|
||||
|
||||
def validate_password(self, value: str) -> str:
|
||||
if not self._has_real_password(value):
|
||||
@@ -285,7 +286,7 @@ class ApplicationConfigurationSerializer(
|
||||
if data[field] == "":
|
||||
data[field] = None
|
||||
# Not a real value, don't overwrite the stored one
|
||||
elif len(data[field].replace("*", "")) == 0:
|
||||
elif is_obfuscated_password(data[field]):
|
||||
del data[field]
|
||||
return super().run_validation(data)
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import pytest
|
||||
|
||||
from paperless.fields import OBFUSCATED_PASSWORD_MASK
|
||||
from paperless.fields import ObfuscatedPasswordField
|
||||
from paperless.fields import is_obfuscated_password
|
||||
|
||||
|
||||
class TestObfuscatedPasswordField:
|
||||
@pytest.mark.parametrize(
|
||||
"secret",
|
||||
[
|
||||
"a",
|
||||
"short",
|
||||
"exactly10!",
|
||||
"a-much-longer-secret-that-should-not-leak-its-length",
|
||||
],
|
||||
)
|
||||
def test_representation_is_constant_regardless_of_length(self, secret: str) -> None:
|
||||
assert (
|
||||
ObfuscatedPasswordField().to_representation(secret)
|
||||
== OBFUSCATED_PASSWORD_MASK
|
||||
)
|
||||
|
||||
|
||||
class TestIsObfuscatedPassword:
|
||||
@pytest.mark.parametrize(
|
||||
("value", "expected"),
|
||||
[
|
||||
("", True),
|
||||
("*", True),
|
||||
("******", True),
|
||||
(OBFUSCATED_PASSWORD_MASK, True),
|
||||
("real-secret", False),
|
||||
("***x***", False),
|
||||
(" ", False),
|
||||
],
|
||||
)
|
||||
def test_detects_placeholder(self, value: str, *, expected: bool) -> None:
|
||||
assert is_obfuscated_password(value) is expected
|
||||
@@ -41,6 +41,7 @@ from documents.models import PaperlessTask
|
||||
from documents.permissions import PaperlessModelPermissions
|
||||
from documents.permissions import PaperlessObjectPermissions
|
||||
from documents.tasks import llmindex_index
|
||||
from paperless.fields import is_obfuscated_password
|
||||
from paperless.filters import GroupFilterSet
|
||||
from paperless.filters import UserFilterSet
|
||||
from paperless.models import ApplicationConfiguration
|
||||
@@ -260,7 +261,7 @@ class ProfileView(GenericAPIView[Any]):
|
||||
user = self.request.user if hasattr(self.request, "user") else None
|
||||
|
||||
password = serializer.validated_data.pop("password", None)
|
||||
if password and password.replace("*", ""):
|
||||
if password and not is_obfuscated_password(password):
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
|
||||
|
||||
@@ -8,23 +8,13 @@ from documents.serialisers import CorrespondentField
|
||||
from documents.serialisers import DocumentTypeField
|
||||
from documents.serialisers import OwnedObjectSerializer
|
||||
from documents.serialisers import TagsField
|
||||
from paperless.fields import ObfuscatedPasswordField
|
||||
from paperless.fields import is_obfuscated_password
|
||||
from paperless_mail.models import MailAccount
|
||||
from paperless_mail.models import MailRule
|
||||
from paperless_mail.models import ProcessedMail
|
||||
|
||||
|
||||
class ObfuscatedPasswordField(serializers.CharField):
|
||||
"""
|
||||
Sends *** string instead of password in the clear
|
||||
"""
|
||||
|
||||
def to_representation(self, value) -> str:
|
||||
return "*" * max(10, len(value))
|
||||
|
||||
def to_internal_value(self, data):
|
||||
return data
|
||||
|
||||
|
||||
class MailAccountSerializer(OwnedObjectSerializer):
|
||||
password = ObfuscatedPasswordField()
|
||||
imap_port = serializers.IntegerField(required=True, allow_null=False)
|
||||
@@ -50,9 +40,8 @@ class MailAccountSerializer(OwnedObjectSerializer):
|
||||
]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
if (
|
||||
"password" in validated_data
|
||||
and len(validated_data.get("password").replace("*", "")) == 0
|
||||
if "password" in validated_data and is_obfuscated_password(
|
||||
validated_data["password"],
|
||||
):
|
||||
validated_data.pop("password")
|
||||
super().update(instance, validated_data)
|
||||
|
||||
@@ -30,6 +30,7 @@ from documents.permissions import PaperlessObjectPermissions
|
||||
from documents.permissions import has_perms_owner_aware
|
||||
from documents.permissions import permitted_object_ids
|
||||
from documents.views import PassUserMixin
|
||||
from paperless.fields import is_obfuscated_password
|
||||
from paperless.views import StandardPagination
|
||||
from paperless_mail.filters import ProcessedMailFilterSet
|
||||
from paperless_mail.mail import MailError
|
||||
@@ -126,9 +127,8 @@ class MailAccountViewSet(PassUserMixin, ModelViewSet[MailAccount]):
|
||||
return HttpResponseForbidden("Insufficient permissions")
|
||||
|
||||
# account exists, use the password from there instead of ***
|
||||
if (
|
||||
len(serializer.validated_data.get("password").replace("*", "")) == 0
|
||||
and existing_account is not None
|
||||
if existing_account is not None and is_obfuscated_password(
|
||||
serializer.validated_data.get("password"),
|
||||
):
|
||||
serializer.validated_data["password"] = existing_account.password
|
||||
serializer.validated_data["account_type"] = existing_account.account_type
|
||||
|
||||
Reference in new issue
Block a user