Compare commits

...

10 Commits

Author SHA1 Message Date
shamoon
a2f4c5aea0 Some Sonar code smell suggestions 2025-09-14 15:58:43 -07:00
shamoon
bc3098419c Update migration 2025-09-14 13:59:03 -07:00
shamoon
82f59ec8b5 Merge branch 'dev' into feature-nested-tags2 2025-09-14 13:58:27 -07:00
GitHub Actions
4905edbf79 Auto translate strings 2025-09-14 03:22:02 +00:00
jojo2357
feb5d534b5 Enhancement: long text custom field (#10846)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-09-14 03:19:00 +00:00
shamoon
d230514dd3 Fix: fix pdf editor hover rotate counterclockwise button (#10848) 2025-09-13 14:19:50 -07:00
shamoon
69143c5e0e Handle parent tag removal in backend 2025-09-13 07:38:08 -07:00
shamoon
09f535f89a Remove unreachable clause 2025-09-12 21:10:18 -07:00
shamoon
08102c95b5 Remove the None case 2025-09-12 21:08:16 -07:00
shamoon
74c864f7f2 Add tree node admin, refactor to share logic 2025-09-12 20:12:48 -07:00
28 changed files with 428 additions and 274 deletions

View File

@@ -534,7 +534,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">366</context>
<context context-type="linenumber">374</context>
</context-group>
</trans-unit>
<trans-unit id="3768927257183755959" datatype="html">
@@ -593,11 +593,11 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">359</context>
<context context-type="linenumber">367</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.html</context>
<context context-type="linenumber">79</context>
<context context-type="linenumber">83</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
@@ -739,7 +739,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">379</context>
<context context-type="linenumber">387</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
@@ -1197,7 +1197,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">335</context>
<context context-type="linenumber">343</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
@@ -1492,7 +1492,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.html</context>
<context context-type="linenumber">77</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.html</context>
@@ -2544,11 +2544,11 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1023</context>
<context context-type="linenumber">1025</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">1388</context>
<context context-type="linenumber">1390</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -3156,7 +3156,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">976</context>
<context context-type="linenumber">978</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -4291,7 +4291,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">301</context>
<context context-type="linenumber">309</context>
</context-group>
</trans-unit>
<trans-unit id="8057014866157903311" datatype="html">
@@ -6611,7 +6611,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">1387</context>
<context context-type="linenumber">1389</context>
</context-group>
</trans-unit>
<trans-unit id="6490688569532630280" datatype="html">
@@ -6764,14 +6764,14 @@
<source>Content</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">231</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="218403386307979629" datatype="html">
<source>Metadata</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">240</context>
<context context-type="linenumber">248</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts</context>
@@ -6782,175 +6782,175 @@
<source>Date modified</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">247</context>
<context context-type="linenumber">255</context>
</context-group>
</trans-unit>
<trans-unit id="6392918669949841614" datatype="html">
<source>Date added</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">259</context>
</context-group>
</trans-unit>
<trans-unit id="146828917013192897" datatype="html">
<source>Media filename</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">255</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit id="4500855521601039868" datatype="html">
<source>Original filename</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">259</context>
<context context-type="linenumber">267</context>
</context-group>
</trans-unit>
<trans-unit id="7985558498848210210" datatype="html">
<source>Original MD5 checksum</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">263</context>
<context context-type="linenumber">271</context>
</context-group>
</trans-unit>
<trans-unit id="5888243105821763422" datatype="html">
<source>Original file size</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">267</context>
<context context-type="linenumber">275</context>
</context-group>
</trans-unit>
<trans-unit id="2696647325713149563" datatype="html">
<source>Original mime type</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">271</context>
<context context-type="linenumber">279</context>
</context-group>
</trans-unit>
<trans-unit id="342875990758166588" datatype="html">
<source>Archive MD5 checksum</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">276</context>
<context context-type="linenumber">284</context>
</context-group>
</trans-unit>
<trans-unit id="6033581412811562084" datatype="html">
<source>Archive file size</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">282</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="6992781481378431874" datatype="html">
<source>Original document metadata</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">299</context>
</context-group>
</trans-unit>
<trans-unit id="2846565152091361585" datatype="html">
<source>Archived document metadata</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">294</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="7206723502037428235" datatype="html">
<source>Notes <x id="START_BLOCK_IF" equiv-text="@if (document?.notes.length) {"/><x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="ngth}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span"/><x id="CLOSE_BLOCK_IF" equiv-text="}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">313,316</context>
<context context-type="linenumber">321,324</context>
</context-group>
</trans-unit>
<trans-unit id="186236568870281953" datatype="html">
<source>History</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">324</context>
<context context-type="linenumber">332</context>
</context-group>
</trans-unit>
<trans-unit id="5129524307369213584" datatype="html">
<source>Save &amp; next</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">361</context>
<context context-type="linenumber">369</context>
</context-group>
</trans-unit>
<trans-unit id="4910102545766233758" datatype="html">
<source>Save &amp; close</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">364</context>
<context context-type="linenumber">372</context>
</context-group>
</trans-unit>
<trans-unit id="1309556917227148591" datatype="html">
<source>Document loading...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">374</context>
<context context-type="linenumber">382</context>
</context-group>
</trans-unit>
<trans-unit id="8191371354890763172" datatype="html">
<source>Enter Password</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">428</context>
<context context-type="linenumber">436</context>
</context-group>
</trans-unit>
<trans-unit id="2218903673684131427" datatype="html">
<source>An error occurred loading content: <x id="PH" equiv-text="err.message ?? 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">414,416</context>
<context context-type="linenumber">416,418</context>
</context-group>
</trans-unit>
<trans-unit id="3200733026060976258" datatype="html">
<source>Document changes detected</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">448</context>
<context context-type="linenumber">450</context>
</context-group>
</trans-unit>
<trans-unit id="2887155916749964" datatype="html">
<source>The version of this document in your browser session appears older than the existing version.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">449</context>
<context context-type="linenumber">451</context>
</context-group>
</trans-unit>
<trans-unit id="237142428785956348" datatype="html">
<source>Saving the document here may overwrite other changes that were made. To restore the existing version, discard your changes or close the document.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">450</context>
<context context-type="linenumber">452</context>
</context-group>
</trans-unit>
<trans-unit id="8720977247725652816" datatype="html">
<source>Ok</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">452</context>
<context context-type="linenumber">454</context>
</context-group>
</trans-unit>
<trans-unit id="6142395741265832184" datatype="html">
<source>Next document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">578</context>
<context context-type="linenumber">580</context>
</context-group>
</trans-unit>
<trans-unit id="651985345816518480" datatype="html">
<source>Previous document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">588</context>
<context context-type="linenumber">590</context>
</context-group>
</trans-unit>
<trans-unit id="2885986061416655600" datatype="html">
<source>Close document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">596</context>
<context context-type="linenumber">598</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
@@ -6961,67 +6961,67 @@
<source>Save document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">603</context>
<context context-type="linenumber">605</context>
</context-group>
</trans-unit>
<trans-unit id="1784543155727940353" datatype="html">
<source>Save and close / next</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">612</context>
<context context-type="linenumber">614</context>
</context-group>
</trans-unit>
<trans-unit id="5758784066858623886" datatype="html">
<source>Error retrieving metadata</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">664</context>
<context context-type="linenumber">666</context>
</context-group>
</trans-unit>
<trans-unit id="3456881259945295697" datatype="html">
<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">693</context>
<context context-type="linenumber">695</context>
</context-group>
</trans-unit>
<trans-unit id="2194092841814123758" datatype="html">
<source>Document &quot;<x id="PH" equiv-text="newValues.title"/>&quot; saved successfully.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">865</context>
<context context-type="linenumber">867</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">889</context>
<context context-type="linenumber">891</context>
</context-group>
</trans-unit>
<trans-unit id="6626387786259219838" datatype="html">
<source>Error saving 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">895</context>
<context context-type="linenumber">897</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">945</context>
<context context-type="linenumber">947</context>
</context-group>
</trans-unit>
<trans-unit id="8410796510716511826" datatype="html">
<source>Do you really want to move the document &quot;<x id="PH" equiv-text="this.document.title"/>&quot; to the trash?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">977</context>
<context context-type="linenumber">979</context>
</context-group>
</trans-unit>
<trans-unit id="282586936710748252" datatype="html">
<source>Documents can be restored prior to permanent deletion.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">978</context>
<context context-type="linenumber">980</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -7032,7 +7032,7 @@
<source>Move to trash</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">980</context>
<context context-type="linenumber">982</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -7043,14 +7043,14 @@
<source>Error deleting document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">999</context>
<context context-type="linenumber">1001</context>
</context-group>
</trans-unit>
<trans-unit id="619486176823357521" datatype="html">
<source>Reprocess confirm</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1019</context>
<context context-type="linenumber">1021</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -7061,81 +7061,81 @@
<source>This operation will permanently recreate the archive file 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">1020</context>
<context context-type="linenumber">1022</context>
</context-group>
</trans-unit>
<trans-unit id="302054111564709516" datatype="html">
<source>The archive file will be re-generated with the current settings.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1021</context>
<context context-type="linenumber">1023</context>
</context-group>
</trans-unit>
<trans-unit id="8251197608401006898" datatype="html">
<source>Reprocess operation for &quot;<x id="PH" equiv-text="this.document.title"/>&quot; 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">1031</context>
<context context-type="linenumber">1033</context>
</context-group>
</trans-unit>
<trans-unit id="4409560272830824468" datatype="html">
<source>Error executing operation</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1042</context>
<context context-type="linenumber">1044</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">1091</context>
<context context-type="linenumber">1093</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">1168</context>
<context context-type="linenumber">1170</context>
</context-group>
</trans-unit>
<trans-unit id="4663705961777238777" datatype="html">
<source>PDF edit operation for &quot;<x id="PH" equiv-text="this.document.title"/>&quot; 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">1406</context>
<context context-type="linenumber">1408</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">1418</context>
<context context-type="linenumber">1420</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">1450</context>
<context context-type="linenumber">1452</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">1458</context>
<context context-type="linenumber">1460</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">1523</context>
<context context-type="linenumber">1525</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">1527</context>
<context context-type="linenumber">1529</context>
</context-group>
</trans-unit>
<trans-unit id="4958946940233632319" datatype="html">
@@ -7560,7 +7560,7 @@
remove <x id="INTERPOLATION"/> custom fields from the selected documents.}}</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.html</context>
<context context-type="linenumber">69,74</context>
<context context-type="linenumber">73,78</context>
</context-group>
</trans-unit>
<trans-unit id="2784168796433474565" datatype="html">
@@ -7699,7 +7699,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">50</context>
<context context-type="linenumber">51</context>
</context-group>
</trans-unit>
<trans-unit id="5145213156408463657" datatype="html">
@@ -9148,56 +9148,63 @@
<source>Boolean</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">18</context>
<context context-type="linenumber">19</context>
</context-group>
</trans-unit>
<trans-unit id="3973931101896534797" datatype="html">
<source>Date</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">22</context>
<context context-type="linenumber">23</context>
</context-group>
</trans-unit>
<trans-unit id="362956598863566327" datatype="html">
<source>Integer</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">26</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="6370642728789544052" datatype="html">
<source>Number</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">30</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="6430409302408843009" datatype="html">
<source>Monetary</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">34</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="6162693758764653365" datatype="html">
<source>Text</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="8308045076391224954" datatype="html">
<source>Url</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">43</context>
</context-group>
</trans-unit>
<trans-unit id="3650316326183661476" datatype="html">
<source>Document Link</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">46</context>
<context context-type="linenumber">47</context>
</context-group>
</trans-unit>
<trans-unit id="2541053474781098515" datatype="html">
<source>Long Text</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/custom-field.ts</context>
<context context-type="linenumber">55</context>
</context-group>
</trans-unit>
<trans-unit id="4460262093225954455" datatype="html">

View File

@@ -35,6 +35,9 @@
@case (CustomFieldDataType.Select) {
<span [ngbTooltip]="nameTooltip">{{getSelectValue(field, value)}}</span>
}
@case (CustomFieldDataType.LongText) {
<p class="mb-0" [ngbTooltip]="nameTooltip">{{value | slice:0:20}}{{value.length > 20 ? '...' : ''}}</p>
}
@default {
<span [ngbTooltip]="nameTooltip">{{value}}</span>
}

View File

@@ -1,5 +1,5 @@
import { CurrencyPipe, getLocaleCurrencyCode } from '@angular/common'
import { Component, Input, LOCALE_ID, OnInit, inject } from '@angular/core'
import { CurrencyPipe, getLocaleCurrencyCode, SlicePipe } from '@angular/common'
import { Component, inject, Input, LOCALE_ID, OnInit } from '@angular/core'
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { takeUntil } from 'rxjs'
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
@@ -14,7 +14,7 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
selector: 'pngx-custom-field-display',
templateUrl: './custom-field-display.component.html',
styleUrl: './custom-field-display.component.scss',
imports: [CustomDatePipe, CurrencyPipe, NgbTooltipModule],
imports: [CustomDatePipe, CurrencyPipe, NgbTooltipModule, SlicePipe],
})
export class CustomFieldDisplayComponent
extends LoadingComponentWithPermissions

View File

@@ -68,6 +68,11 @@
[allowNull]="true"
[horizontal]="true"></pngx-input-select>
}
@case (CustomFieldDataType.LongText) {
<pngx-input-textarea [(ngModel)]="value[fieldId]" (ngModelChange)="onChange(value)"
[title]="getCustomField(fieldId)?.name"
class="flex-grow-1"></pngx-input-textarea>
}
}
<button type="button" class="btn btn-link text-danger" (click)="removeSelectedField.next(fieldId)">
<i-bs name="trash"></i-bs>

View File

@@ -24,6 +24,7 @@ import { MonetaryComponent } from '../monetary/monetary.component'
import { NumberComponent } from '../number/number.component'
import { SelectComponent } from '../select/select.component'
import { TextComponent } from '../text/text.component'
import { TextAreaComponent } from '../textarea/textarea.component'
import { UrlComponent } from '../url/url.component'
@Component({
@@ -51,6 +52,7 @@ import { UrlComponent } from '../url/url.component'
ReactiveFormsModule,
RouterModule,
NgxBootstrapIconsModule,
TextAreaComponent,
],
})
export class CustomFieldsValuesComponent extends AbstractInputComponent<Object> {

View File

@@ -4,6 +4,7 @@ import {
NG_VALUE_ACCESSOR,
ReactiveFormsModule,
} from '@angular/forms'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { AbstractInputComponent } from '../abstract-input'
@@ -18,7 +19,12 @@ import { AbstractInputComponent } from '../abstract-input'
selector: 'pngx-input-textarea',
templateUrl: './textarea.component.html',
styleUrls: ['./textarea.component.scss'],
imports: [FormsModule, ReactiveFormsModule, SafeHtmlPipe],
imports: [
FormsModule,
ReactiveFormsModule,
SafeHtmlPipe,
NgxBootstrapIconsModule,
],
})
export class TextAreaComponent extends AbstractInputComponent<string> {
@Input()

View File

@@ -30,7 +30,7 @@
<div class="page-item rounded p-2" cdkDrag (click)="toggleSelection(i)" [class.selected]="p.selected">
<div class="btn-toolbar hover-actions z-10">
<div class="btn-group me-2">
<button class="btn btn-sm btn-dark" (click)="rotate(i); $event.stopPropagation()" title="Rotate page counter-clockwise" i18n-title>
<button class="btn btn-sm btn-dark" (click)="rotate(i, true); $event.stopPropagation()" title="Rotate page counter-clockwise" i18n-title>
<i-bs name="arrow-counterclockwise"></i-bs>
</button>
<button class="btn btn-sm btn-dark" (click)="rotate(i); $event.stopPropagation()" title="Rotate page clockwise" i18n-title>

View File

@@ -67,8 +67,9 @@ export class PDFEditorComponent extends ConfirmDialogComponent {
this.pages[i].selected = !this.pages[i].selected
}
rotate(i: number) {
this.pages[i].rotate = (this.pages[i].rotate + 90) % 360
rotate(i: number, counterclockwise: boolean = false) {
this.pages[i].rotate =
(this.pages[i].rotate + (counterclockwise ? -90 : 90) + 360) % 360
}
rotateSelected(dir: number) {

View File

@@ -216,6 +216,14 @@
(removed)="removeField(fieldInstance)"
[error]="getCustomFieldError(i)"></pngx-input-select>
}
@case (CustomFieldDataType.LongText) {
<pngx-input-textarea formControlName="value"
[title]="getCustomFieldFromInstance(fieldInstance)?.name"
[removable]="userCanEdit"
(removed)="removeField(fieldInstance)"
[horizontal]="true"
[error]="getCustomFieldError(i)"></pngx-input-textarea>
}
}
</div>
}

View File

@@ -98,6 +98,7 @@ import { PermissionsFormComponent } from '../common/input/permissions/permission
import { SelectComponent } from '../common/input/select/select.component'
import { TagsComponent } from '../common/input/tags/tags.component'
import { TextComponent } from '../common/input/text/text.component'
import { TextAreaComponent } from '../common/input/textarea/textarea.component'
import { UrlComponent } from '../common/input/url/url.component'
import { PageHeaderComponent } from '../common/page-header/page-header.component'
import {
@@ -173,6 +174,7 @@ export enum ZoomSetting {
NgbDropdownModule,
NgxBootstrapIconsModule,
PdfViewerModule,
TextAreaComponent,
],
})
export class DocumentDetailComponent

View File

@@ -56,6 +56,10 @@
[items]="field.extra_data.select_options" bindLabel="label" [allowNull]="true" [horizontal]="true">
</pngx-input-select>
}
@case (CustomFieldDataType.LongText) {
<pngx-input-textarea formControlName="{{field.id}}" class="w-100" [title]="field.name" [horizontal]="true">
</pngx-input-textarea>
}
}
<button type="button" class="btn btn-outline-danger mb-3" (click)="removeField(field.id)">
<i-bs name="x"></i-bs>

View File

@@ -18,6 +18,7 @@ import { TextComponent } from 'src/app/components/common/input/text/text.compone
import { UrlComponent } from 'src/app/components/common/input/url/url.component'
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
import { DocumentService } from 'src/app/services/rest/document.service'
import { TextAreaComponent } from '../../../common/input/textarea/textarea.component'
@Component({
selector: 'pngx-custom-fields-bulk-edit-dialog',
@@ -35,6 +36,7 @@ import { DocumentService } from 'src/app/services/rest/document.service'
FormsModule,
ReactiveFormsModule,
NgxBootstrapIconsModule,
TextAreaComponent,
],
})
export class CustomFieldsBulkEditDialogComponent {

View File

@@ -114,6 +114,10 @@ export const CUSTOM_FIELD_QUERY_OPERATOR_GROUPS_BY_TYPE = {
CustomFieldQueryOperatorGroups.Exact,
CustomFieldQueryOperatorGroups.Subset,
],
[CustomFieldDataType.LongText]: [
CustomFieldQueryOperatorGroups.Basic,
CustomFieldQueryOperatorGroups.String,
],
}
export const CUSTOM_FIELD_QUERY_VALUE_TYPES_BY_OPERATOR = {

View File

@@ -10,6 +10,7 @@ export enum CustomFieldDataType {
Monetary = 'monetary',
DocumentLink = 'documentlink',
Select = 'select',
LongText = 'longtext',
}
export const DATA_TYPE_LABELS = [
@@ -49,6 +50,10 @@ export const DATA_TYPE_LABELS = [
id: CustomFieldDataType.Select,
name: $localize`Select`,
},
{
id: CustomFieldDataType.LongText,
name: $localize`Long Text`,
},
]
export interface CustomField extends ObjectWithId {

View File

@@ -34,17 +34,17 @@ describe('flattenTags', () => {
expect(flat.map((t) => t.orderIndex)).toEqual([0, 1, 2, 3, 4, 5, 6])
// Children are rebuilt
const aRoot = flat.find((t) => t.name === 'A-root')!
const aRoot = flat.find((t) => t.name === 'A-root')
expect(new Set(aRoot.children?.map((c) => c.name))).toEqual(
new Set(['child 2', 'Child 10'])
)
const bRoot = flat.find((t) => t.name === 'B-root')!
const bRoot = flat.find((t) => t.name === 'B-root')
expect(new Set(bRoot.children?.map((c) => c.name))).toEqual(
new Set(['Alpha', 'beta'])
)
const child2 = flat.find((t) => t.name === 'child 2')!
const child2 = flat.find((t) => t.name === 'child 2')
expect(new Set(child2.children?.map((c) => c.name))).toEqual(
new Set(['Sub 1'])
)

View File

@@ -8,7 +8,7 @@ export function flattenTags(all: Tag[]): Tag[] {
for (const t of map.values()) {
if (t.parent) {
const p = map.get(t.parent)
p && p.children.push(t)
p?.children.push(t)
}
}
const roots = Array.from(map.values()).filter((t) => !t.parent)
@@ -29,6 +29,7 @@ export function flattenTags(all: Tag[]): Tag[] {
}
}
}
roots.sort(sortByName).forEach((r) => walk(r, 0))
roots.sort(sortByName)
roots.forEach((r) => walk(r, 0))
return ordered
}

View File

@@ -1,6 +1,7 @@
from django.conf import settings
from django.contrib import admin
from guardian.admin import GuardedModelAdmin
from treenode.admin import TreeNodeModelAdmin
from documents.models import Correspondent
from documents.models import CustomField
@@ -14,6 +15,7 @@ from documents.models import SavedViewFilterRule
from documents.models import ShareLink
from documents.models import StoragePath
from documents.models import Tag
from documents.tasks import update_document_parent_tags
if settings.AUDIT_LOG_ENABLED:
from auditlog.admin import LogEntryAdmin
@@ -26,12 +28,25 @@ class CorrespondentAdmin(GuardedModelAdmin):
list_editable = ("match", "matching_algorithm")
class TagAdmin(GuardedModelAdmin):
class TagAdmin(GuardedModelAdmin, TreeNodeModelAdmin):
list_display = ("name", "color", "match", "matching_algorithm")
list_filter = ("matching_algorithm",)
list_editable = ("color", "match", "matching_algorithm")
search_fields = ("color", "name")
def save_model(self, request, obj, form, change):
old_parent = None
if change and obj.pk:
tag = Tag.objects.get(pk=obj.pk)
old_parent = tag.get_parent() if tag else None
super().save_model(request, obj, form, change)
# sync parent tags on documents if changed
new_parent = obj.get_parent()
if new_parent and old_parent != new_parent:
update_document_parent_tags(obj, new_parent)
class DocumentTypeAdmin(GuardedModelAdmin):
list_display = ("name", "match", "matching_algorithm")

View File

@@ -230,6 +230,7 @@ class CustomFieldsFilter(Filter):
| qs.filter(custom_fields__value_monetary__icontains=value)
| qs.filter(custom_fields__value_document_ids__icontains=value)
| qs.filter(custom_fields__value_select__in=option_ids)
| qs.filter(custom_fields__value_long_text__icontains=value)
)
else:
return qs
@@ -314,6 +315,7 @@ class CustomFieldQueryParser:
CustomField.FieldDataType.MONETARY: ("basic", "string", "arithmetic"),
CustomField.FieldDataType.DOCUMENTLINK: ("basic", "containment"),
CustomField.FieldDataType.SELECT: ("basic",),
CustomField.FieldDataType.LONG_TEXT: ("basic", "string"),
}
DATE_COMPONENTS = [
@@ -845,7 +847,10 @@ class DocumentsOrderingFilter(OrderingFilter):
annotation = None
match field.data_type:
case CustomField.FieldDataType.STRING:
case (
CustomField.FieldDataType.STRING
| CustomField.FieldDataType.LONG_TEXT
):
annotation = Subquery(
CustomFieldInstance.objects.filter(
document_id=OuterRef("id"),

View File

@@ -0,0 +1,39 @@
# Generated by Django 5.2.6 on 2025-09-13 17:11
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1069_workflowtrigger_filter_has_storage_path_and_more"),
]
operations = [
migrations.AddField(
model_name="customfieldinstance",
name="value_long_text",
field=models.TextField(null=True),
),
migrations.AlterField(
model_name="customfield",
name="data_type",
field=models.CharField(
choices=[
("string", "String"),
("url", "URL"),
("date", "Date"),
("boolean", "Boolean"),
("integer", "Integer"),
("float", "Float"),
("monetary", "Monetary"),
("documentlink", "Document Link"),
("select", "Select"),
("longtext", "Long Text"),
],
editable=False,
max_length=50,
verbose_name="data type",
),
),
]

View File

@@ -8,7 +8,7 @@ from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "1069_workflowtrigger_filter_has_storage_path_and_more"),
("documents", "1070_customfieldinstance_value_long_text_and_more"),
]
operations = [

View File

@@ -790,6 +790,7 @@ class CustomField(models.Model):
MONETARY = ("monetary", _("Monetary"))
DOCUMENTLINK = ("documentlink", _("Document Link"))
SELECT = ("select", _("Select"))
LONG_TEXT = ("longtext", _("Long Text"))
created = models.DateTimeField(
_("created"),
@@ -847,6 +848,7 @@ class CustomFieldInstance(SoftDeleteModel):
CustomField.FieldDataType.MONETARY: "value_monetary",
CustomField.FieldDataType.DOCUMENTLINK: "value_document_ids",
CustomField.FieldDataType.SELECT: "value_select",
CustomField.FieldDataType.LONG_TEXT: "value_long_text",
}
created = models.DateTimeField(
@@ -914,6 +916,8 @@ class CustomFieldInstance(SoftDeleteModel):
value_select = models.CharField(null=True, max_length=16)
value_long_text = models.TextField(null=True)
class Meta:
ordering = ("created",)
verbose_name = _("custom field instance")

View File

@@ -608,9 +608,6 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
# Temporarily set tn_parent in-memory to validate clean()
self.instance.tn_parent = parent
self.instance.clean()
except ValueError as e:
logger.debug("Tag parent validation failed: %s", e)
raise serializers.ValidationError({"parent": _("Invalid parent tag.")})
except ValidationError as e:
logger.debug("Tag parent validation failed: %s", e)
raise e
@@ -1091,22 +1088,27 @@ class DocumentSerializer(
doc_id,
)
if "tags" in validated_data:
# add all parent tags
all_ancestor_tags = set(validated_data["tags"])
for tag in validated_data["tags"]:
all_ancestor_tags.update(tag.get_ancestors())
validated_data["tags"] = list(all_ancestor_tags)
# remove any children for parents that are being removed
tag_parents_being_removed = [
tag
for tag in instance.tags.all()
if tag not in validated_data["tags"] and tag.get_children_count() > 0
]
validated_data["tags"] = [
tag
for tag in validated_data["tags"]
if tag not in tag_parents_being_removed
]
# Respect tag hierarchy on updates:
# - Adding a child adds its ancestors
# - Removing a parent removes all its descendants
prev_tags = set(instance.tags.all())
requested_tags = set(validated_data["tags"])
# Tags being removed in this update and all descendants
removed_tags = prev_tags - requested_tags
blocked_tags = set(removed_tags)
for t in removed_tags:
blocked_tags.update(t.get_descendants())
# Add all parent tags
final_tags = set(requested_tags)
for t in requested_tags:
final_tags.update(t.get_ancestors())
# Drop removed parents and their descendants
final_tags.difference_update(blocked_tags)
validated_data["tags"] = list(final_tags)
if validated_data.get("remove_inbox_tags"):
tag_ids_being_added = (
[

View File

@@ -515,3 +515,41 @@ def check_scheduled_workflows():
workflow_to_run=workflow,
document=document,
)
def update_document_parent_tags(tag: Tag, new_parent: Tag) -> None:
"""
When a tag's parent changes, ensure all documents containing the tag also have
the parent tag (and its ancestors) applied.
"""
doc_tag_relationship = Document.tags.through
doc_ids: list[int] = list(
Document.objects.filter(tags=tag).values_list("pk", flat=True),
)
if not doc_ids:
return
parents_to_add = [new_parent, *new_parent.get_ancestors()]
to_create: list = []
affected: set[int] = set()
for parent in parents_to_add:
missing_qs = Document.objects.filter(id__in=doc_ids).exclude(tags=parent)
missing_ids = list(missing_qs.values_list("pk", flat=True))
to_create.extend(
doc_tag_relationship(document_id=doc_id, tag_id=parent.id)
for doc_id in missing_ids
)
affected.update(missing_ids)
if to_create:
doc_tag_relationship.objects.bulk_create(
to_create,
ignore_conflicts=True,
)
if affected:
bulk_update_documents.delay(document_ids=list(affected))

View File

@@ -202,6 +202,7 @@ def get_custom_fields_context(
CustomField.FieldDataType.MONETARY,
CustomField.FieldDataType.STRING,
CustomField.FieldDataType.URL,
CustomField.FieldDataType.LONG_TEXT,
}:
value = pathvalidate.sanitize_filename(
field_instance.value,

View File

@@ -1,4 +1,5 @@
import types
from unittest.mock import patch
from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import User
@@ -7,7 +8,9 @@ from django.utils import timezone
from documents import index
from documents.admin import DocumentAdmin
from documents.admin import TagAdmin
from documents.models import Document
from documents.models import Tag
from documents.tests.utils import DirectoriesMixin
from paperless.admin import PaperlessUserAdmin
@@ -70,6 +73,24 @@ class TestDocumentAdmin(DirectoriesMixin, TestCase):
self.assertEqual(self.doc_admin.created_(doc), "2020-04-12")
class TestTagAdmin(DirectoriesMixin, TestCase):
def setUp(self) -> None:
super().setUp()
self.tag_admin = TagAdmin(model=Tag, admin_site=AdminSite())
@patch("documents.tasks.bulk_update_documents")
def test_parent_tags_get_added(self, mock_bulk_update):
document = Document.objects.create(title="test")
parent = Tag.objects.create(name="parent")
child = Tag.objects.create(name="child")
document.tags.add(child)
child.tn_parent = parent
self.tag_admin.save_model(None, child, None, change=True)
document.refresh_from_db()
self.assertIn(parent, document.tags.all())
class TestPaperlessAdmin(DirectoriesMixin, TestCase):
def setUp(self) -> None:
super().setUp()

View File

@@ -31,16 +31,6 @@ class TestTagHierarchy(APITestCase):
mime_type="application/pdf",
)
def test_api_add_child_adds_parent(self):
self.client.patch(
f"/api/documents/{self.document.pk}/",
{"tags": [self.child.pk]},
format="json",
)
self.document.refresh_from_db()
tags = set(self.document.tags.values_list("pk", flat=True))
assert tags == {self.parent.pk, self.child.pk}
def test_document_api_add_child_adds_parent(self):
self.client.patch(
f"/api/documents/{self.document.pk}/",
@@ -51,6 +41,16 @@ class TestTagHierarchy(APITestCase):
tags = set(self.document.tags.values_list("pk", flat=True))
assert tags == {self.parent.pk, self.child.pk}
def test_document_api_remove_parent_removes_children(self):
self.document.add_nested_tags([self.parent, self.child])
self.client.patch(
f"/api/documents/{self.document.pk}/",
{"tags": [self.child.pk]},
format="json",
)
self.document.refresh_from_db()
assert self.document.tags.count() == 0
def test_document_api_remove_parent_removes_child(self):
self.document.add_nested_tags([self.child])
self.client.patch(

View File

@@ -169,6 +169,7 @@ from documents.tasks import empty_trash
from documents.tasks import index_optimize
from documents.tasks import sanity_check
from documents.tasks import train_classifier
from documents.tasks import update_document_parent_tags
from documents.templating.filepath import validate_filepath_template_and_render
from documents.utils import get_boolean
from paperless import version
@@ -345,34 +346,8 @@ class TagViewSet(ModelViewSet, PermissionsAwareDocumentCountMixin):
old_parent = self.get_object().get_parent()
tag = serializer.save()
new_parent = tag.get_parent()
if old_parent != new_parent:
self._update_document_parent_tags(tag, old_parent, new_parent)
def _update_document_parent_tags(self, tag, old_parent, new_parent):
DocumentTagRelationship = Document.tags.through
doc_ids = list(Document.objects.filter(tags=tag).values_list("pk", flat=True))
affected = set()
if new_parent:
parents_to_add = [new_parent, *new_parent.get_ancestors()]
to_create = []
for parent in parents_to_add:
missing = Document.objects.filter(id__in=doc_ids).exclude(tags=parent)
to_create.extend(
DocumentTagRelationship(document_id=doc_id, tag_id=parent.id)
for doc_id in missing.values_list("pk", flat=True)
)
affected.update(missing.values_list("pk", flat=True))
if to_create:
DocumentTagRelationship.objects.bulk_create(
to_create,
ignore_conflicts=True,
)
if affected:
from documents.tasks import bulk_update_documents
bulk_update_documents.delay(document_ids=list(affected))
if new_parent and old_parent != new_parent:
update_document_parent_tags(tag, new_parent)
@extend_schema_view(**generate_object_with_permissions_schema(DocumentTypeSerializer))

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-11 17:43+0000\n"
"POT-Creation-Date: 2025-09-14 03:21+0000\n"
"PO-Revision-Date: 2022-02-17 04:17\n"
"Last-Translator: \n"
"Language-Team: English\n"
@@ -21,39 +21,39 @@ msgstr ""
msgid "Documents"
msgstr ""
#: documents/filters.py:384
#: documents/filters.py:386
msgid "Value must be valid JSON."
msgstr ""
#: documents/filters.py:403
#: documents/filters.py:405
msgid "Invalid custom field query expression"
msgstr ""
#: documents/filters.py:413
#: documents/filters.py:415
msgid "Invalid expression list. Must be nonempty."
msgstr ""
#: documents/filters.py:434
#: documents/filters.py:436
msgid "Invalid logical operator {op!r}"
msgstr ""
#: documents/filters.py:448
#: documents/filters.py:450
msgid "Maximum number of query conditions exceeded."
msgstr ""
#: documents/filters.py:513
#: documents/filters.py:515
msgid "{name!r} is not a valid custom field."
msgstr ""
#: documents/filters.py:550
#: documents/filters.py:552
msgid "{data_type} does not support query expr {expr!r}."
msgstr ""
#: documents/filters.py:658
#: documents/filters.py:660
msgid "Maximum nesting depth exceeded."
msgstr ""
#: documents/filters.py:843
#: documents/filters.py:845
msgid "Custom field not found"
msgstr ""
@@ -61,27 +61,27 @@ msgstr ""
msgid "owner"
msgstr ""
#: documents/models.py:53 documents/models.py:946
#: documents/models.py:53 documents/models.py:950
msgid "None"
msgstr ""
#: documents/models.py:54 documents/models.py:947
#: documents/models.py:54 documents/models.py:951
msgid "Any word"
msgstr ""
#: documents/models.py:55 documents/models.py:948
#: documents/models.py:55 documents/models.py:952
msgid "All words"
msgstr ""
#: documents/models.py:56 documents/models.py:949
#: documents/models.py:56 documents/models.py:953
msgid "Exact match"
msgstr ""
#: documents/models.py:57 documents/models.py:950
#: documents/models.py:57 documents/models.py:954
msgid "Regular expression"
msgstr ""
#: documents/models.py:58 documents/models.py:951
#: documents/models.py:58 documents/models.py:955
msgid "Fuzzy word"
msgstr ""
@@ -89,20 +89,20 @@ msgstr ""
msgid "Automatic"
msgstr ""
#: documents/models.py:62 documents/models.py:423 documents/models.py:1447
#: documents/models.py:62 documents/models.py:423 documents/models.py:1451
#: paperless_mail/models.py:23 paperless_mail/models.py:143
msgid "name"
msgstr ""
#: documents/models.py:64 documents/models.py:1015
#: documents/models.py:64 documents/models.py:1019
msgid "match"
msgstr ""
#: documents/models.py:67 documents/models.py:1018
#: documents/models.py:67 documents/models.py:1022
msgid "matching algorithm"
msgstr ""
#: documents/models.py:72 documents/models.py:1023
#: documents/models.py:72 documents/models.py:1027
msgid "is insensitive"
msgstr ""
@@ -207,7 +207,7 @@ msgid "The number of pages of the document."
msgstr ""
#: documents/models.py:217 documents/models.py:655 documents/models.py:693
#: documents/models.py:764 documents/models.py:822
#: documents/models.py:765 documents/models.py:824
msgid "created"
msgstr ""
@@ -256,7 +256,7 @@ msgid "The position of this document in your physical document archive."
msgstr ""
#: documents/models.py:294 documents/models.py:666 documents/models.py:720
#: documents/models.py:1490
#: documents/models.py:1494
msgid "document"
msgstr ""
@@ -280,11 +280,11 @@ msgstr ""
msgid "Title"
msgstr ""
#: documents/models.py:410 documents/models.py:967
#: documents/models.py:410 documents/models.py:971
msgid "Created"
msgstr ""
#: documents/models.py:411 documents/models.py:966
#: documents/models.py:411 documents/models.py:970
msgid "Added"
msgstr ""
@@ -752,430 +752,434 @@ msgstr ""
msgid "Select"
msgstr ""
#: documents/models.py:773
#: documents/models.py:762
msgid "Long Text"
msgstr ""
#: documents/models.py:774
msgid "data type"
msgstr ""
#: documents/models.py:780
#: documents/models.py:781
msgid "extra data"
msgstr ""
#: documents/models.py:784
#: documents/models.py:785
msgid "Extra data for the custom field, such as select options"
msgstr ""
#: documents/models.py:790
#: documents/models.py:791
msgid "custom field"
msgstr ""
#: documents/models.py:791
#: documents/models.py:792
msgid "custom fields"
msgstr ""
#: documents/models.py:888
#: documents/models.py:892
msgid "custom field instance"
msgstr ""
#: documents/models.py:889
#: documents/models.py:893
msgid "custom field instances"
msgstr ""
#: documents/models.py:954
#: documents/models.py:958
msgid "Consumption Started"
msgstr ""
#: documents/models.py:955
#: documents/models.py:959
msgid "Document Added"
msgstr ""
#: documents/models.py:956
#: documents/models.py:960
msgid "Document Updated"
msgstr ""
#: documents/models.py:957
#: documents/models.py:961
msgid "Scheduled"
msgstr ""
#: documents/models.py:960
#: documents/models.py:964
msgid "Consume Folder"
msgstr ""
#: documents/models.py:961
#: documents/models.py:965
msgid "Api Upload"
msgstr ""
#: documents/models.py:962
#: documents/models.py:966
msgid "Mail Fetch"
msgstr ""
#: documents/models.py:963
#: documents/models.py:967
msgid "Web UI"
msgstr ""
#: documents/models.py:968
#: documents/models.py:972
msgid "Modified"
msgstr ""
#: documents/models.py:969
#: documents/models.py:973
msgid "Custom Field"
msgstr ""
#: documents/models.py:972
#: documents/models.py:976
msgid "Workflow Trigger Type"
msgstr ""
#: documents/models.py:984
#: documents/models.py:988
msgid "filter path"
msgstr ""
#: documents/models.py:989
#: documents/models.py:993
msgid ""
"Only consume documents with a path that matches this if specified. Wildcards "
"specified as * are allowed. Case insensitive."
msgstr ""
#: documents/models.py:996
#: documents/models.py:1000
msgid "filter filename"
msgstr ""
#: documents/models.py:1001 paperless_mail/models.py:200
#: documents/models.py:1005 paperless_mail/models.py:200
msgid ""
"Only consume documents which entirely match this filename if specified. "
"Wildcards such as *.pdf or *invoice* are allowed. Case insensitive."
msgstr ""
#: documents/models.py:1012
#: documents/models.py:1016
msgid "filter documents from this mail rule"
msgstr ""
#: documents/models.py:1028
#: documents/models.py:1032
msgid "has these tag(s)"
msgstr ""
#: documents/models.py:1036
#: documents/models.py:1040
msgid "has this document type"
msgstr ""
#: documents/models.py:1044
#: documents/models.py:1048
msgid "has this correspondent"
msgstr ""
#: documents/models.py:1052
#: documents/models.py:1056
msgid "has this storage path"
msgstr ""
#: documents/models.py:1056
#: documents/models.py:1060
msgid "schedule offset days"
msgstr ""
#: documents/models.py:1059
#: documents/models.py:1063
msgid "The number of days to offset the schedule trigger by."
msgstr ""
#: documents/models.py:1064
#: documents/models.py:1068
msgid "schedule is recurring"
msgstr ""
#: documents/models.py:1067
#: documents/models.py:1071
msgid "If the schedule should be recurring."
msgstr ""
#: documents/models.py:1072
#: documents/models.py:1076
msgid "schedule recurring delay in days"
msgstr ""
#: documents/models.py:1076
#: documents/models.py:1080
msgid "The number of days between recurring schedule triggers."
msgstr ""
#: documents/models.py:1081
#: documents/models.py:1085
msgid "schedule date field"
msgstr ""
#: documents/models.py:1086
#: documents/models.py:1090
msgid "The field to check for a schedule trigger."
msgstr ""
#: documents/models.py:1095
#: documents/models.py:1099
msgid "schedule date custom field"
msgstr ""
#: documents/models.py:1099
#: documents/models.py:1103
msgid "workflow trigger"
msgstr ""
#: documents/models.py:1100
#: documents/models.py:1104
msgid "workflow triggers"
msgstr ""
#: documents/models.py:1108
#: documents/models.py:1112
msgid "email subject"
msgstr ""
#: documents/models.py:1112
#: documents/models.py:1116
msgid ""
"The subject of the email, can include some placeholders, see documentation."
msgstr ""
#: documents/models.py:1118
#: documents/models.py:1122
msgid "email body"
msgstr ""
#: documents/models.py:1121
#: documents/models.py:1125
msgid ""
"The body (message) of the email, can include some placeholders, see "
"documentation."
msgstr ""
#: documents/models.py:1127
#: documents/models.py:1131
msgid "emails to"
msgstr ""
#: documents/models.py:1130
#: documents/models.py:1134
msgid "The destination email addresses, comma separated."
msgstr ""
#: documents/models.py:1136
#: documents/models.py:1140
msgid "include document in email"
msgstr ""
#: documents/models.py:1147
#: documents/models.py:1151
msgid "webhook url"
msgstr ""
#: documents/models.py:1150
#: documents/models.py:1154
msgid "The destination URL for the notification."
msgstr ""
#: documents/models.py:1155
#: documents/models.py:1159
msgid "use parameters"
msgstr ""
#: documents/models.py:1160
#: documents/models.py:1164
msgid "send as JSON"
msgstr ""
#: documents/models.py:1164
#: documents/models.py:1168
msgid "webhook parameters"
msgstr ""
#: documents/models.py:1167
#: documents/models.py:1171
msgid "The parameters to send with the webhook URL if body not used."
msgstr ""
#: documents/models.py:1171
#: documents/models.py:1175
msgid "webhook body"
msgstr ""
#: documents/models.py:1174
#: documents/models.py:1178
msgid "The body to send with the webhook URL if parameters not used."
msgstr ""
#: documents/models.py:1178
#: documents/models.py:1182
msgid "webhook headers"
msgstr ""
#: documents/models.py:1181
#: documents/models.py:1185
msgid "The headers to send with the webhook URL."
msgstr ""
#: documents/models.py:1186
#: documents/models.py:1190
msgid "include document in webhook"
msgstr ""
#: documents/models.py:1197
#: documents/models.py:1201
msgid "Assignment"
msgstr ""
#: documents/models.py:1201
#: documents/models.py:1205
msgid "Removal"
msgstr ""
#: documents/models.py:1205 documents/templates/account/password_reset.html:15
#: documents/models.py:1209 documents/templates/account/password_reset.html:15
msgid "Email"
msgstr ""
#: documents/models.py:1209
#: documents/models.py:1213
msgid "Webhook"
msgstr ""
#: documents/models.py:1213
#: documents/models.py:1217
msgid "Workflow Action Type"
msgstr ""
#: documents/models.py:1219
#: documents/models.py:1223
msgid "assign title"
msgstr ""
#: documents/models.py:1223
#: documents/models.py:1227
msgid "Assign a document title, must be a Jinja2 template, see documentation."
msgstr ""
#: documents/models.py:1231 paperless_mail/models.py:274
#: documents/models.py:1235 paperless_mail/models.py:274
msgid "assign this tag"
msgstr ""
#: documents/models.py:1240 paperless_mail/models.py:282
#: documents/models.py:1244 paperless_mail/models.py:282
msgid "assign this document type"
msgstr ""
#: documents/models.py:1249 paperless_mail/models.py:296
#: documents/models.py:1253 paperless_mail/models.py:296
msgid "assign this correspondent"
msgstr ""
#: documents/models.py:1258
#: documents/models.py:1262
msgid "assign this storage path"
msgstr ""
#: documents/models.py:1267
#: documents/models.py:1271
msgid "assign this owner"
msgstr ""
#: documents/models.py:1274
#: documents/models.py:1278
msgid "grant view permissions to these users"
msgstr ""
#: documents/models.py:1281
#: documents/models.py:1285
msgid "grant view permissions to these groups"
msgstr ""
#: documents/models.py:1288
#: documents/models.py:1292
msgid "grant change permissions to these users"
msgstr ""
#: documents/models.py:1295
#: documents/models.py:1299
msgid "grant change permissions to these groups"
msgstr ""
#: documents/models.py:1302
#: documents/models.py:1306
msgid "assign these custom fields"
msgstr ""
#: documents/models.py:1306
#: documents/models.py:1310
msgid "custom field values"
msgstr ""
#: documents/models.py:1310
#: documents/models.py:1314
msgid "Optional values to assign to the custom fields."
msgstr ""
#: documents/models.py:1319
#: documents/models.py:1323
msgid "remove these tag(s)"
msgstr ""
#: documents/models.py:1324
#: documents/models.py:1328
msgid "remove all tags"
msgstr ""
#: documents/models.py:1331
#: documents/models.py:1335
msgid "remove these document type(s)"
msgstr ""
#: documents/models.py:1336
#: documents/models.py:1340
msgid "remove all document types"
msgstr ""
#: documents/models.py:1343
#: documents/models.py:1347
msgid "remove these correspondent(s)"
msgstr ""
#: documents/models.py:1348
#: documents/models.py:1352
msgid "remove all correspondents"
msgstr ""
#: documents/models.py:1355
#: documents/models.py:1359
msgid "remove these storage path(s)"
msgstr ""
#: documents/models.py:1360
#: documents/models.py:1364
msgid "remove all storage paths"
msgstr ""
#: documents/models.py:1367
#: documents/models.py:1371
msgid "remove these owner(s)"
msgstr ""
#: documents/models.py:1372
#: documents/models.py:1376
msgid "remove all owners"
msgstr ""
#: documents/models.py:1379
#: documents/models.py:1383
msgid "remove view permissions for these users"
msgstr ""
#: documents/models.py:1386
#: documents/models.py:1390
msgid "remove view permissions for these groups"
msgstr ""
#: documents/models.py:1393
#: documents/models.py:1397
msgid "remove change permissions for these users"
msgstr ""
#: documents/models.py:1400
#: documents/models.py:1404
msgid "remove change permissions for these groups"
msgstr ""
#: documents/models.py:1405
#: documents/models.py:1409
msgid "remove all permissions"
msgstr ""
#: documents/models.py:1412
#: documents/models.py:1416
msgid "remove these custom fields"
msgstr ""
#: documents/models.py:1417
#: documents/models.py:1421
msgid "remove all custom fields"
msgstr ""
#: documents/models.py:1426
#: documents/models.py:1430
msgid "email"
msgstr ""
#: documents/models.py:1435
#: documents/models.py:1439
msgid "webhook"
msgstr ""
#: documents/models.py:1439
#: documents/models.py:1443
msgid "workflow action"
msgstr ""
#: documents/models.py:1440
#: documents/models.py:1444
msgid "workflow actions"
msgstr ""
#: documents/models.py:1449 paperless_mail/models.py:145
#: documents/models.py:1453 paperless_mail/models.py:145
msgid "order"
msgstr ""
#: documents/models.py:1455
#: documents/models.py:1459
msgid "triggers"
msgstr ""
#: documents/models.py:1462
#: documents/models.py:1466
msgid "actions"
msgstr ""
#: documents/models.py:1465 paperless_mail/models.py:154
#: documents/models.py:1469 paperless_mail/models.py:154
msgid "enabled"
msgstr ""
#: documents/models.py:1476
#: documents/models.py:1480
msgid "workflow"
msgstr ""
#: documents/models.py:1480
#: documents/models.py:1484
msgid "workflow trigger type"
msgstr ""
#: documents/models.py:1494
#: documents/models.py:1498
msgid "date run"
msgstr ""
#: documents/models.py:1500
#: documents/models.py:1504
msgid "workflow run"
msgstr ""
#: documents/models.py:1501
#: documents/models.py:1505
msgid "workflow runs"
msgstr ""