mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-22 17:54:40 -05:00
Compare commits
7 Commits
bcb0ae1ee5
...
ce5d4e9c92
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ce5d4e9c92 | ||
![]() |
0ab85b5122 | ||
![]() |
2c9e690dfb | ||
![]() |
344cc70cd5 | ||
![]() |
73f0f1212d | ||
![]() |
a61f5ac64c | ||
![]() |
6a5be992c0 |
@ -406,7 +406,8 @@ Currently, there are three events that correspond to workflow trigger 'types':
|
|||||||
3. **Document Updated**: when a document is updated. Similar to 'added' events, triggers can include filtering by content matching,
|
3. **Document Updated**: when a document is updated. Similar to 'added' events, triggers can include filtering by content matching,
|
||||||
tags, doc type, or correspondent.
|
tags, doc type, or correspondent.
|
||||||
4. **Scheduled**: a scheduled trigger that can be used to run workflows at a specific time. The date used can be either the document
|
4. **Scheduled**: a scheduled trigger that can be used to run workflows at a specific time. The date used can be either the document
|
||||||
added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date.
|
added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date (positive
|
||||||
|
offsets will trigger before the date, negative offsets will trigger after).
|
||||||
|
|
||||||
The following flow diagram illustrates the three document trigger types:
|
The following flow diagram illustrates the three document trigger types:
|
||||||
|
|
||||||
|
13
src-ui/__mocks__/pdfjs-dist.ts
Normal file
13
src-ui/__mocks__/pdfjs-dist.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export const getDocument = jest.fn(() => ({
|
||||||
|
promise: Promise.resolve({ numPages: 3 }),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const GlobalWorkerOptions = { workerSrc: '' }
|
||||||
|
export const VerbosityLevel = { ERRORS: 0 }
|
||||||
|
|
||||||
|
globalThis.pdfjsLib = {
|
||||||
|
getDocument,
|
||||||
|
GlobalWorkerOptions,
|
||||||
|
VerbosityLevel,
|
||||||
|
AbortException: class AbortException extends Error {},
|
||||||
|
}
|
@ -1284,19 +1284,19 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">201</context>
|
<context context-type="linenumber">209</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">220</context>
|
<context context-type="linenumber">228</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">287</context>
|
<context context-type="linenumber">295</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">306</context>
|
<context context-type="linenumber">314</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
|
||||||
@ -1319,19 +1319,19 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">209</context>
|
<context context-type="linenumber">217</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">228</context>
|
<context context-type="linenumber">236</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">295</context>
|
<context context-type="linenumber">303</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">314</context>
|
<context context-type="linenumber">322</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
|
||||||
@ -1357,11 +1357,11 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">234</context>
|
<context context-type="linenumber">242</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">320</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
|
||||||
@ -3691,7 +3691,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">163</context>
|
<context context-type="linenumber">171</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6457471243969293847" datatype="html">
|
<trans-unit id="6457471243969293847" datatype="html">
|
||||||
@ -4115,7 +4115,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">188</context>
|
<context context-type="linenumber">196</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4754802869258527587" datatype="html">
|
<trans-unit id="4754802869258527587" datatype="html">
|
||||||
@ -4133,7 +4133,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">189</context>
|
<context context-type="linenumber">197</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1519954996184640001" datatype="html">
|
<trans-unit id="1519954996184640001" datatype="html">
|
||||||
@ -4645,381 +4645,388 @@
|
|||||||
<source>Offset days</source>
|
<source>Offset days</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">126</context>
|
<context context-type="linenumber">128</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1488741788768120127" datatype="html">
|
||||||
|
<source>Positive values will trigger the workflow before the date, negative values after.</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">132</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3726450101884717309" datatype="html">
|
<trans-unit id="3726450101884717309" datatype="html">
|
||||||
<source>Relative to</source>
|
<source>Relative to</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">129</context>
|
<context context-type="linenumber">137</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3878884308536053934" datatype="html">
|
<trans-unit id="3878884308536053934" datatype="html">
|
||||||
<source>Custom field</source>
|
<source>Custom field</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">133</context>
|
<context context-type="linenumber">141</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1088170562604583291" datatype="html">
|
<trans-unit id="1088170562604583291" datatype="html">
|
||||||
<source>Custom field to use for date.</source>
|
<source>Custom field to use for date.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">133</context>
|
<context context-type="linenumber">141</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1011433830042635014" datatype="html">
|
<trans-unit id="1011433830042635014" datatype="html">
|
||||||
<source>Recurring</source>
|
<source>Recurring</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">139</context>
|
<context context-type="linenumber">147</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1421663004162437543" datatype="html">
|
<trans-unit id="1421663004162437543" datatype="html">
|
||||||
<source>Trigger is recurring.</source>
|
<source>Trigger is recurring.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">139</context>
|
<context context-type="linenumber">147</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5937989815294159481" datatype="html">
|
<trans-unit id="5937989815294159481" datatype="html">
|
||||||
<source>Recurring interval days</source>
|
<source>Recurring interval days</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">143</context>
|
<context context-type="linenumber">151</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="722765958672682251" datatype="html">
|
<trans-unit id="722765958672682251" datatype="html">
|
||||||
<source>Repeat the trigger every n days.</source>
|
<source>Repeat the trigger every n days.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">143</context>
|
<context context-type="linenumber">151</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8727727835543352574" datatype="html">
|
<trans-unit id="8727727835543352574" datatype="html">
|
||||||
<source>Trigger for documents that match <x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="<em>"/>all<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="</em>"/> filters specified below.</source>
|
<source>Trigger for documents that match <x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="<em>"/>all<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="</em>"/> filters specified below.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">148</context>
|
<context context-type="linenumber">156</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7467799586957602479" datatype="html">
|
<trans-unit id="7467799586957602479" datatype="html">
|
||||||
<source>Filter filename</source>
|
<source>Filter filename</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">151</context>
|
<context context-type="linenumber">159</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3694878959415278689" datatype="html">
|
<trans-unit id="3694878959415278689" datatype="html">
|
||||||
<source>Apply to documents that match this filename. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.</source>
|
<source>Apply to documents that match this filename. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">151</context>
|
<context context-type="linenumber">159</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1473412958770421458" datatype="html">
|
<trans-unit id="1473412958770421458" datatype="html">
|
||||||
<source>Filter sources</source>
|
<source>Filter sources</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">153</context>
|
<context context-type="linenumber">161</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6540860478788535250" datatype="html">
|
<trans-unit id="6540860478788535250" datatype="html">
|
||||||
<source>Filter path</source>
|
<source>Filter path</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">154</context>
|
<context context-type="linenumber">162</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5491897741674893121" datatype="html">
|
<trans-unit id="5491897741674893121" datatype="html">
|
||||||
<source>Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a></source>
|
<source>Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a></source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">154</context>
|
<context context-type="linenumber">162</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7468453896129193641" datatype="html">
|
<trans-unit id="7468453896129193641" datatype="html">
|
||||||
<source>Filter mail rule</source>
|
<source>Filter mail rule</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">155</context>
|
<context context-type="linenumber">163</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8663702115863339485" datatype="html">
|
<trans-unit id="8663702115863339485" datatype="html">
|
||||||
<source>Apply to documents consumed via this mail rule.</source>
|
<source>Apply to documents consumed via this mail rule.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">155</context>
|
<context context-type="linenumber">163</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6840369584127435743" datatype="html">
|
<trans-unit id="6840369584127435743" datatype="html">
|
||||||
<source>Content matching algorithm</source>
|
<source>Content matching algorithm</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">158</context>
|
<context context-type="linenumber">166</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="510635115034690805" datatype="html">
|
<trans-unit id="510635115034690805" datatype="html">
|
||||||
<source>Content matching pattern</source>
|
<source>Content matching pattern</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">160</context>
|
<context context-type="linenumber">168</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3484236514968690689" datatype="html">
|
<trans-unit id="3484236514968690689" datatype="html">
|
||||||
<source>Has any of tags</source>
|
<source>Has any of tags</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">169</context>
|
<context context-type="linenumber">177</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5281365940563983618" datatype="html">
|
<trans-unit id="5281365940563983618" datatype="html">
|
||||||
<source>Has correspondent</source>
|
<source>Has correspondent</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">170</context>
|
<context context-type="linenumber">178</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4806713133917046341" datatype="html">
|
<trans-unit id="4806713133917046341" datatype="html">
|
||||||
<source>Has document type</source>
|
<source>Has document type</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">171</context>
|
<context context-type="linenumber">179</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6417103744331194518" datatype="html">
|
<trans-unit id="6417103744331194518" datatype="html">
|
||||||
<source>Action type</source>
|
<source>Action type</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">181</context>
|
<context context-type="linenumber">189</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6019822389883736115" datatype="html">
|
<trans-unit id="6019822389883736115" datatype="html">
|
||||||
<source>Assign title</source>
|
<source>Assign title</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">186</context>
|
<context context-type="linenumber">194</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1098196422099517191" datatype="html">
|
<trans-unit id="1098196422099517191" datatype="html">
|
||||||
<source>Can include some placeholders, see <a target='_blank' href='https://docs.paperless-ngx.com/usage/#workflows'>documentation</a>.</source>
|
<source>Can include some placeholders, see <a target='_blank' href='https://docs.paperless-ngx.com/usage/#workflows'>documentation</a>.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">186</context>
|
<context context-type="linenumber">194</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6528897010417701530" datatype="html">
|
<trans-unit id="6528897010417701530" datatype="html">
|
||||||
<source>Assign tags</source>
|
<source>Assign tags</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">187</context>
|
<context context-type="linenumber">195</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7198346314713788799" datatype="html">
|
<trans-unit id="7198346314713788799" datatype="html">
|
||||||
<source>Assign storage path</source>
|
<source>Assign storage path</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">190</context>
|
<context context-type="linenumber">198</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="475685412372379925" datatype="html">
|
<trans-unit id="475685412372379925" datatype="html">
|
||||||
<source>Assign custom fields</source>
|
<source>Assign custom fields</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">191</context>
|
<context context-type="linenumber">199</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5057200219587080996" datatype="html">
|
<trans-unit id="5057200219587080996" datatype="html">
|
||||||
<source>Assign owner</source>
|
<source>Assign owner</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">195</context>
|
<context context-type="linenumber">203</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1749184201773078639" datatype="html">
|
<trans-unit id="1749184201773078639" datatype="html">
|
||||||
<source>Assign view permissions</source>
|
<source>Assign view permissions</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">197</context>
|
<context context-type="linenumber">205</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1744964187586405039" datatype="html">
|
<trans-unit id="1744964187586405039" datatype="html">
|
||||||
<source>Assign edit permissions</source>
|
<source>Assign edit permissions</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">216</context>
|
<context context-type="linenumber">224</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6236311670364192011" datatype="html">
|
<trans-unit id="6236311670364192011" datatype="html">
|
||||||
<source>Remove tags</source>
|
<source>Remove tags</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">243</context>
|
<context context-type="linenumber">251</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7890599006071681081" datatype="html">
|
<trans-unit id="7890599006071681081" datatype="html">
|
||||||
<source>Remove all</source>
|
<source>Remove all</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">244</context>
|
<context context-type="linenumber">252</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">250</context>
|
<context context-type="linenumber">258</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">256</context>
|
<context context-type="linenumber">264</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">262</context>
|
<context context-type="linenumber">270</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">268</context>
|
<context context-type="linenumber">276</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">275</context>
|
<context context-type="linenumber">283</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">281</context>
|
<context context-type="linenumber">289</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8636414563726517994" datatype="html">
|
<trans-unit id="8636414563726517994" datatype="html">
|
||||||
<source>Remove correspondents</source>
|
<source>Remove correspondents</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">249</context>
|
<context context-type="linenumber">257</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5305293055593064952" datatype="html">
|
<trans-unit id="5305293055593064952" datatype="html">
|
||||||
<source>Remove document types</source>
|
<source>Remove document types</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">255</context>
|
<context context-type="linenumber">263</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2400388879708187" datatype="html">
|
<trans-unit id="2400388879708187" datatype="html">
|
||||||
<source>Remove storage paths</source>
|
<source>Remove storage paths</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">261</context>
|
<context context-type="linenumber">269</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4324304327041955720" datatype="html">
|
<trans-unit id="4324304327041955720" datatype="html">
|
||||||
<source>Remove custom fields</source>
|
<source>Remove custom fields</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">267</context>
|
<context context-type="linenumber">275</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8367536502602515064" datatype="html">
|
<trans-unit id="8367536502602515064" datatype="html">
|
||||||
<source>Remove owners</source>
|
<source>Remove owners</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">274</context>
|
<context context-type="linenumber">282</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3393772184866313281" datatype="html">
|
<trans-unit id="3393772184866313281" datatype="html">
|
||||||
<source>Remove permissions</source>
|
<source>Remove permissions</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">280</context>
|
<context context-type="linenumber">288</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3145629643370481114" datatype="html">
|
<trans-unit id="3145629643370481114" datatype="html">
|
||||||
<source>View permissions</source>
|
<source>View permissions</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">283</context>
|
<context context-type="linenumber">291</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1946660694635960249" datatype="html">
|
<trans-unit id="1946660694635960249" datatype="html">
|
||||||
<source>Edit permissions</source>
|
<source>Edit permissions</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">302</context>
|
<context context-type="linenumber">310</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8987736563240025468" datatype="html">
|
<trans-unit id="8987736563240025468" datatype="html">
|
||||||
<source>Email subject</source>
|
<source>Email subject</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">330</context>
|
<context context-type="linenumber">338</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8239445959209739142" datatype="html">
|
<trans-unit id="8239445959209739142" datatype="html">
|
||||||
<source>Email body</source>
|
<source>Email body</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">339</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1222152280703048012" datatype="html">
|
<trans-unit id="1222152280703048012" datatype="html">
|
||||||
<source>Email recipients</source>
|
<source>Email recipients</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">332</context>
|
<context context-type="linenumber">340</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7916910101279824329" datatype="html">
|
<trans-unit id="7916910101279824329" datatype="html">
|
||||||
<source>Attach document</source>
|
<source>Attach document</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">333</context>
|
<context context-type="linenumber">341</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5028001922785731600" datatype="html">
|
<trans-unit id="5028001922785731600" datatype="html">
|
||||||
<source>Webhook url</source>
|
<source>Webhook url</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">341</context>
|
<context context-type="linenumber">349</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7491983459027245019" datatype="html">
|
<trans-unit id="7491983459027245019" datatype="html">
|
||||||
<source>Use parameters for webhook body</source>
|
<source>Use parameters for webhook body</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">343</context>
|
<context context-type="linenumber">351</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4078214298308732810" datatype="html">
|
<trans-unit id="4078214298308732810" datatype="html">
|
||||||
<source>Send webhook payload as JSON</source>
|
<source>Send webhook payload as JSON</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">344</context>
|
<context context-type="linenumber">352</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6806149889743731985" datatype="html">
|
<trans-unit id="6806149889743731985" datatype="html">
|
||||||
<source>Webhook params</source>
|
<source>Webhook params</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">347</context>
|
<context context-type="linenumber">355</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7089924379374330" datatype="html">
|
<trans-unit id="7089924379374330" datatype="html">
|
||||||
<source>Webhook body</source>
|
<source>Webhook body</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">349</context>
|
<context context-type="linenumber">357</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3829826512656746316" datatype="html">
|
<trans-unit id="3829826512656746316" datatype="html">
|
||||||
<source>Webhook headers</source>
|
<source>Webhook headers</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">351</context>
|
<context context-type="linenumber">359</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2114525789021600887" datatype="html">
|
<trans-unit id="2114525789021600887" datatype="html">
|
||||||
<source>Include document</source>
|
<source>Include document</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">352</context>
|
<context context-type="linenumber">360</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4626030417479279989" datatype="html">
|
<trans-unit id="4626030417479279989" datatype="html">
|
||||||
@ -7901,7 +7908,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">90</context>
|
<context context-type="linenumber">91</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="329406837759048287" datatype="html">
|
<trans-unit id="329406837759048287" datatype="html">
|
||||||
@ -8248,7 +8255,18 @@
|
|||||||
<source>Initiating upload...</source>
|
<source>Initiating upload...</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/file-drop/file-drop.component.ts</context>
|
<context context-type="sourcefile">src/app/components/file-drop/file-drop.component.ts</context>
|
||||||
<context context-type="linenumber">93</context>
|
<context context-type="linenumber">139</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/file-drop/file-drop.component.ts</context>
|
||||||
|
<context context-type="linenumber">148</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="146335022760474171" datatype="html">
|
||||||
|
<source>Failed to read dropped items: <x id="PH" equiv-text="e.message"/></source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/file-drop/file-drop.component.ts</context>
|
||||||
|
<context context-type="linenumber">144</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6316128875819022658" datatype="html">
|
<trans-unit id="6316128875819022658" datatype="html">
|
||||||
@ -9260,102 +9278,186 @@
|
|||||||
<context context-type="linenumber">51</context>
|
<context context-type="linenumber">51</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="7943546022633063836" datatype="html">
|
||||||
|
<source>Barcode Settings</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">52</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="1313137480169642057" datatype="html">
|
<trans-unit id="1313137480169642057" datatype="html">
|
||||||
<source>Output Type</source>
|
<source>Output Type</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">75</context>
|
<context context-type="linenumber">76</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2826581353496868063" datatype="html">
|
<trans-unit id="2826581353496868063" datatype="html">
|
||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">83</context>
|
<context context-type="linenumber">84</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1713271461473302108" datatype="html">
|
<trans-unit id="1713271461473302108" datatype="html">
|
||||||
<source>Mode</source>
|
<source>Mode</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">97</context>
|
<context context-type="linenumber">98</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6114528299376689399" datatype="html">
|
<trans-unit id="6114528299376689399" datatype="html">
|
||||||
<source>Skip Archive File</source>
|
<source>Skip Archive File</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">105</context>
|
<context context-type="linenumber">106</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1115402553541327390" datatype="html">
|
<trans-unit id="1115402553541327390" datatype="html">
|
||||||
<source>Image DPI</source>
|
<source>Image DPI</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">113</context>
|
<context context-type="linenumber">114</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6352596107300820129" datatype="html">
|
<trans-unit id="6352596107300820129" datatype="html">
|
||||||
<source>Clean</source>
|
<source>Clean</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">120</context>
|
<context context-type="linenumber">121</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="725308589819024010" datatype="html">
|
<trans-unit id="725308589819024010" datatype="html">
|
||||||
<source>Deskew</source>
|
<source>Deskew</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">128</context>
|
<context context-type="linenumber">129</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6256076128297775802" datatype="html">
|
<trans-unit id="6256076128297775802" datatype="html">
|
||||||
<source>Rotate Pages</source>
|
<source>Rotate Pages</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">135</context>
|
<context context-type="linenumber">136</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8527188778859256947" datatype="html">
|
<trans-unit id="8527188778859256947" datatype="html">
|
||||||
<source>Rotate Pages Threshold</source>
|
<source>Rotate Pages Threshold</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">142</context>
|
<context context-type="linenumber">143</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3762131309176747817" datatype="html">
|
<trans-unit id="3762131309176747817" datatype="html">
|
||||||
<source>Max Image Pixels</source>
|
<source>Max Image Pixels</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">149</context>
|
<context context-type="linenumber">150</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7846583355792281769" datatype="html">
|
<trans-unit id="7846583355792281769" datatype="html">
|
||||||
<source>Color Conversion Strategy</source>
|
<source>Color Conversion Strategy</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">156</context>
|
<context context-type="linenumber">157</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4696480417479207939" datatype="html">
|
<trans-unit id="4696480417479207939" datatype="html">
|
||||||
<source>OCR Arguments</source>
|
<source>OCR Arguments</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">164</context>
|
<context context-type="linenumber">165</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7106327322456204362" datatype="html">
|
<trans-unit id="7106327322456204362" datatype="html">
|
||||||
<source>Application Logo</source>
|
<source>Application Logo</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">171</context>
|
<context context-type="linenumber">172</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2684743776608068095" datatype="html">
|
<trans-unit id="2684743776608068095" datatype="html">
|
||||||
<source>Application Title</source>
|
<source>Application Title</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
<context context-type="linenumber">178</context>
|
<context context-type="linenumber">179</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4763207540517250026" datatype="html">
|
||||||
|
<source>Enable Barcodes</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">186</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5111693440737450705" datatype="html">
|
||||||
|
<source>Enable TIFF Support</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">193</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7024102701648099736" datatype="html">
|
||||||
|
<source>Barcode String</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">200</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5496493538285104278" datatype="html">
|
||||||
|
<source>Retain Split Pages</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">207</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3585266363073659539" datatype="html">
|
||||||
|
<source>Enable ASN</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">214</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2563883192247717052" datatype="html">
|
||||||
|
<source>ASN Prefix</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">221</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="876335624277968161" datatype="html">
|
||||||
|
<source>Upscale</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">228</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3330040801415354394" datatype="html">
|
||||||
|
<source>DPI</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">235</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="2056636654483201493" datatype="html">
|
||||||
|
<source>Max Pages</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">242</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7410804727457548947" datatype="html">
|
||||||
|
<source>Enable Tag Detection</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">249</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="3723784143052004117" datatype="html">
|
||||||
|
<source>Tag Mapping</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
|
||||||
|
<context context-type="linenumber">256</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5948496158474272829" datatype="html">
|
<trans-unit id="5948496158474272829" datatype="html">
|
||||||
@ -9826,28 +9928,28 @@
|
|||||||
<source>Connecting...</source>
|
<source>Connecting...</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
||||||
<context context-type="linenumber">43</context>
|
<context context-type="linenumber">27</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1245343823699368872" datatype="html">
|
<trans-unit id="1245343823699368872" datatype="html">
|
||||||
<source>Uploading...</source>
|
<source>Uploading...</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
||||||
<context context-type="linenumber">55</context>
|
<context context-type="linenumber">39</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7446520539098045935" datatype="html">
|
<trans-unit id="7446520539098045935" datatype="html">
|
||||||
<source>Upload complete, waiting...</source>
|
<source>Upload complete, waiting...</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
||||||
<context context-type="linenumber">58</context>
|
<context context-type="linenumber">42</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1405142710727603568" datatype="html">
|
<trans-unit id="1405142710727603568" datatype="html">
|
||||||
<source>HTTP error: <x id="PH" equiv-text="error.status"/> <x id="PH_1" equiv-text="error.statusText"/></source>
|
<source>HTTP error: <x id="PH" equiv-text="error.status"/> <x id="PH_1" equiv-text="error.statusText"/></source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
<context context-type="sourcefile">src/app/services/upload-documents.service.ts</context>
|
||||||
<context context-type="linenumber">71</context>
|
<context context-type="linenumber">55</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2119857572761283468" datatype="html">
|
<trans-unit id="2119857572761283468" datatype="html">
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"test": "ng test --no-watch --coverage",
|
"test": "ng test --no-watch --coverage",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint"
|
||||||
"postinstall": "patch-package"
|
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -33,7 +32,6 @@
|
|||||||
"ngx-color": "^10.0.0",
|
"ngx-color": "^10.0.0",
|
||||||
"ngx-cookie-service": "^19.1.2",
|
"ngx-cookie-service": "^19.1.2",
|
||||||
"ngx-device-detector": "^9.0.0",
|
"ngx-device-detector": "^9.0.0",
|
||||||
"ngx-file-drop": "^16.0.0",
|
|
||||||
"ngx-ui-tour-ng-bootstrap": "^16.0.0",
|
"ngx-ui-tour-ng-bootstrap": "^16.0.0",
|
||||||
"rxjs": "^7.8.2",
|
"rxjs": "^7.8.2",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
@ -67,7 +65,6 @@
|
|||||||
"jest-junit": "^16.0.0",
|
"jest-junit": "^16.0.0",
|
||||||
"jest-preset-angular": "^14.5.5",
|
"jest-preset-angular": "^14.5.5",
|
||||||
"jest-websocket-mock": "^2.5.0",
|
"jest-websocket-mock": "^2.5.0",
|
||||||
"patch-package": "^8.0.0",
|
|
||||||
"prettier-plugin-organize-imports": "^4.1.0",
|
"prettier-plugin-organize-imports": "^4.1.0",
|
||||||
"ts-node": "~10.9.1",
|
"ts-node": "~10.9.1",
|
||||||
"typescript": "^5.5.4"
|
"typescript": "^5.5.4"
|
||||||
|
File diff suppressed because one or more lines are too long
224
src-ui/pnpm-lock.yaml
generated
224
src-ui/pnpm-lock.yaml
generated
@ -71,12 +71,9 @@ importers:
|
|||||||
ngx-device-detector:
|
ngx-device-detector:
|
||||||
specifier: ^9.0.0
|
specifier: ^9.0.0
|
||||||
version: 9.0.0(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))
|
version: 9.0.0(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))
|
||||||
ngx-file-drop:
|
|
||||||
specifier: ^16.0.0
|
|
||||||
version: 16.0.0(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))
|
|
||||||
ngx-ui-tour-ng-bootstrap:
|
ngx-ui-tour-ng-bootstrap:
|
||||||
specifier: ^16.0.0
|
specifier: ^16.0.0
|
||||||
version: 16.0.0(nfyq54qpjcnpjhdwpvrgi4nyra)
|
version: 16.0.0(9bfbf45bdfd1029869b23707ee6bb312)
|
||||||
rxjs:
|
rxjs:
|
||||||
specifier: ^7.8.2
|
specifier: ^7.8.2
|
||||||
version: 7.8.2
|
version: 7.8.2
|
||||||
@ -98,7 +95,7 @@ importers:
|
|||||||
version: 19.0.1(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9)(@angular/localize@19.2.9(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9))(@types/node@22.15.3)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.3)(ts-node@10.9.2(@types/node@22.15.3)(typescript@5.5.4)))(jiti@1.21.7)(typescript@5.5.4)(vite@6.2.7(@types/node@22.15.3)(jiti@1.21.7)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.7.0))(yaml@2.7.0)
|
version: 19.0.1(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9)(@angular/localize@19.2.9(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9))(@types/node@22.15.3)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.3)(ts-node@10.9.2(@types/node@22.15.3)(typescript@5.5.4)))(jiti@1.21.7)(typescript@5.5.4)(vite@6.2.7(@types/node@22.15.3)(jiti@1.21.7)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.7.0))(yaml@2.7.0)
|
||||||
'@angular-builders/jest':
|
'@angular-builders/jest':
|
||||||
specifier: ^19.0.1
|
specifier: ^19.0.1
|
||||||
version: 19.0.1(2xzflpchozqzu223xxigbxxvgu)
|
version: 19.0.1(025d537e0c22047bb48e08c4eeeaebf1)
|
||||||
'@angular-devkit/build-angular':
|
'@angular-devkit/build-angular':
|
||||||
specifier: ^19.2.10
|
specifier: ^19.2.10
|
||||||
version: 19.2.10(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9)(@angular/localize@19.2.9(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9))(@types/node@22.15.3)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.3)(ts-node@10.9.2(@types/node@22.15.3)(typescript@5.5.4)))(jiti@1.21.7)(typescript@5.5.4)(vite@6.2.7(@types/node@22.15.3)(jiti@1.21.7)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.7.0))(yaml@2.7.0)
|
version: 19.2.10(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9)(@angular/localize@19.2.9(@angular/compiler-cli@19.2.9(@angular/compiler@19.2.9)(typescript@5.5.4))(@angular/compiler@19.2.9))(@types/node@22.15.3)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.15.3)(ts-node@10.9.2(@types/node@22.15.3)(typescript@5.5.4)))(jiti@1.21.7)(typescript@5.5.4)(vite@6.2.7(@types/node@22.15.3)(jiti@1.21.7)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.7.0))(yaml@2.7.0)
|
||||||
@ -168,9 +165,6 @@ importers:
|
|||||||
jest-websocket-mock:
|
jest-websocket-mock:
|
||||||
specifier: ^2.5.0
|
specifier: ^2.5.0
|
||||||
version: 2.5.0
|
version: 2.5.0
|
||||||
patch-package:
|
|
||||||
specifier: ^8.0.0
|
|
||||||
version: 8.0.0
|
|
||||||
prettier-plugin-organize-imports:
|
prettier-plugin-organize-imports:
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.0(prettier@3.4.2)(typescript@5.5.4)
|
version: 4.1.0(prettier@3.4.2)(typescript@5.5.4)
|
||||||
@ -2780,10 +2774,6 @@ packages:
|
|||||||
asynckit@0.4.0:
|
asynckit@0.4.0:
|
||||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
at-least-node@1.0.0:
|
|
||||||
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
|
||||||
engines: {node: '>= 4.0.0'}
|
|
||||||
|
|
||||||
autoprefixer@10.4.20:
|
autoprefixer@10.4.20:
|
||||||
resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
|
resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
@ -2931,10 +2921,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
call-bind@1.0.7:
|
|
||||||
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
call-bound@1.0.4:
|
call-bound@1.0.4:
|
||||||
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
|
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -3226,10 +3212,6 @@ packages:
|
|||||||
defaults@1.0.4:
|
defaults@1.0.4:
|
||||||
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
|
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
|
||||||
|
|
||||||
define-data-property@1.1.4:
|
|
||||||
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
define-lazy-prop@3.0.0:
|
define-lazy-prop@3.0.0:
|
||||||
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
|
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -3607,9 +3589,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
|
resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
||||||
find-yarn-workspace-root@2.0.0:
|
|
||||||
resolution: {integrity: sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==}
|
|
||||||
|
|
||||||
flat-cache@4.0.1:
|
flat-cache@4.0.1:
|
||||||
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
|
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@ -3652,10 +3631,6 @@ packages:
|
|||||||
fs-constants@1.0.0:
|
fs-constants@1.0.0:
|
||||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||||
|
|
||||||
fs-extra@9.1.0:
|
|
||||||
resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
|
|
||||||
fs-minipass@2.1.0:
|
fs-minipass@2.1.0:
|
||||||
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
|
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@ -3692,10 +3667,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
|
resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
get-intrinsic@1.2.7:
|
|
||||||
resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -3763,9 +3734,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
has-property-descriptors@1.0.2:
|
|
||||||
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
|
|
||||||
|
|
||||||
has-symbols@1.1.0:
|
has-symbols@1.1.0:
|
||||||
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -3943,11 +3911,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-docker@2.2.1:
|
|
||||||
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
is-docker@3.0.0:
|
is-docker@3.0.0:
|
||||||
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
|
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
@ -4020,10 +3983,6 @@ packages:
|
|||||||
is-what@3.14.1:
|
is-what@3.14.1:
|
||||||
resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
|
resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
|
||||||
|
|
||||||
is-wsl@2.2.0:
|
|
||||||
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
|
|
||||||
is-wsl@3.1.0:
|
is-wsl@3.1.0:
|
||||||
resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
|
resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@ -4031,9 +3990,6 @@ packages:
|
|||||||
isarray@1.0.0:
|
isarray@1.0.0:
|
||||||
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||||
|
|
||||||
isarray@2.0.5:
|
|
||||||
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
|
|
||||||
|
|
||||||
isexe@2.0.0:
|
isexe@2.0.0:
|
||||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||||
|
|
||||||
@ -4310,10 +4266,6 @@ packages:
|
|||||||
json-stable-stringify-without-jsonify@1.0.1:
|
json-stable-stringify-without-jsonify@1.0.1:
|
||||||
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
||||||
|
|
||||||
json-stable-stringify@1.1.0:
|
|
||||||
resolution: {integrity: sha512-zfA+5SuwYN2VWqN1/5HZaDzQKLJHaBVMZIIM+wuYjdptkaQsqzDdqjqf+lZZJUuJq1aanHiY8LhH8LmH+qBYJA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
json5@2.2.3:
|
json5@2.2.3:
|
||||||
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
|
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -4322,12 +4274,6 @@ packages:
|
|||||||
jsonc-parser@3.3.1:
|
jsonc-parser@3.3.1:
|
||||||
resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
|
resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
|
||||||
|
|
||||||
jsonfile@6.1.0:
|
|
||||||
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
|
||||||
|
|
||||||
jsonify@0.0.1:
|
|
||||||
resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==}
|
|
||||||
|
|
||||||
jsonparse@1.3.1:
|
jsonparse@1.3.1:
|
||||||
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
|
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
|
||||||
engines: {'0': node >= 0.2.0}
|
engines: {'0': node >= 0.2.0}
|
||||||
@ -4342,9 +4288,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
klaw-sync@6.0.0:
|
|
||||||
resolution: {integrity: sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==}
|
|
||||||
|
|
||||||
kleur@3.0.3:
|
kleur@3.0.3:
|
||||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -4708,13 +4651,6 @@ packages:
|
|||||||
'@angular/common': ^19.0.0
|
'@angular/common': ^19.0.0
|
||||||
'@angular/core': ^19.0.0
|
'@angular/core': ^19.0.0
|
||||||
|
|
||||||
ngx-file-drop@16.0.0:
|
|
||||||
resolution: {integrity: sha512-33RPoZBAiMkV110Rzu3iOrzGcG5M20S4sAiwLzNylfJobu9qVw5XR83FhUelSeqJRoaDxXBRKAozYCSnUf2CNw==}
|
|
||||||
engines: {node: '>= 14.5.0', npm: '>= 6.9.0'}
|
|
||||||
peerDependencies:
|
|
||||||
'@angular/common': '>=14.0.0'
|
|
||||||
'@angular/core': '>=14.0.0'
|
|
||||||
|
|
||||||
ngx-ui-tour-core@14.0.0:
|
ngx-ui-tour-core@14.0.0:
|
||||||
resolution: {integrity: sha512-6pzzEwxn/gCS3puEXDqgINBRbhvhzHYjmiA9DTCNEx1dPfYwjZVmPqNvNeZIVHucVnVZViAAKvA6MTc3Gm7aOw==}
|
resolution: {integrity: sha512-6pzzEwxn/gCS3puEXDqgINBRbhvhzHYjmiA9DTCNEx1dPfYwjZVmPqNvNeZIVHucVnVZViAAKvA6MTc3Gm7aOw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -4814,10 +4750,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
|
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
object-keys@1.1.1:
|
|
||||||
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
obuf@1.1.2:
|
obuf@1.1.2:
|
||||||
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
|
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
|
||||||
|
|
||||||
@ -4844,10 +4776,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
|
resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
open@7.4.2:
|
|
||||||
resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
|
|
||||||
optionator@0.9.4:
|
optionator@0.9.4:
|
||||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@ -4935,11 +4863,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
patch-package@8.0.0:
|
|
||||||
resolution: {integrity: sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==}
|
|
||||||
engines: {node: '>=14', npm: '>5'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
path-exists@4.0.0:
|
path-exists@4.0.0:
|
||||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -5265,11 +5188,6 @@ packages:
|
|||||||
rfdc@1.4.1:
|
rfdc@1.4.1:
|
||||||
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
|
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
|
||||||
|
|
||||||
rimraf@2.7.1:
|
|
||||||
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
|
|
||||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
rollup@4.34.8:
|
rollup@4.34.8:
|
||||||
resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==}
|
resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==}
|
||||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
@ -5369,10 +5287,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
|
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
set-function-length@1.2.1:
|
|
||||||
resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
setprototypeof@1.1.0:
|
setprototypeof@1.1.0:
|
||||||
resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==}
|
resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==}
|
||||||
|
|
||||||
@ -5434,10 +5348,6 @@ packages:
|
|||||||
sisteransi@1.0.5:
|
sisteransi@1.0.5:
|
||||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||||
|
|
||||||
slash@2.0.0:
|
|
||||||
resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
|
|
||||||
slash@3.0.0:
|
slash@3.0.0:
|
||||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -5825,10 +5735,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
|
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
|
||||||
engines: {node: '>= 4.0.0'}
|
engines: {node: '>= 4.0.0'}
|
||||||
|
|
||||||
universalify@2.0.1:
|
|
||||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
|
||||||
engines: {node: '>= 10.0.0'}
|
|
||||||
|
|
||||||
unpipe@1.0.0:
|
unpipe@1.0.0:
|
||||||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@ -6233,7 +6139,7 @@ snapshots:
|
|||||||
- webpack-cli
|
- webpack-cli
|
||||||
- yaml
|
- yaml
|
||||||
|
|
||||||
'@angular-builders/jest@19.0.1(2xzflpchozqzu223xxigbxxvgu)':
|
'@angular-builders/jest@19.0.1(025d537e0c22047bb48e08c4eeeaebf1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@angular-builders/common': 3.0.1(@types/node@22.15.3)(chokidar@4.0.3)(typescript@5.5.4)
|
'@angular-builders/common': 3.0.1(@types/node@22.15.3)(chokidar@4.0.3)(typescript@5.5.4)
|
||||||
'@angular-devkit/architect': 0.1902.8(chokidar@4.0.3)
|
'@angular-devkit/architect': 0.1902.8(chokidar@4.0.3)
|
||||||
@ -8995,8 +8901,6 @@ snapshots:
|
|||||||
|
|
||||||
asynckit@0.4.0: {}
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
at-least-node@1.0.0: {}
|
|
||||||
|
|
||||||
autoprefixer@10.4.20(postcss@8.5.2):
|
autoprefixer@10.4.20(postcss@8.5.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.24.4
|
browserslist: 4.24.4
|
||||||
@ -9215,14 +9119,6 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
call-bind@1.0.7:
|
|
||||||
dependencies:
|
|
||||||
es-define-property: 1.0.1
|
|
||||||
es-errors: 1.3.0
|
|
||||||
function-bind: 1.1.2
|
|
||||||
get-intrinsic: 1.2.7
|
|
||||||
set-function-length: 1.2.1
|
|
||||||
|
|
||||||
call-bound@1.0.4:
|
call-bound@1.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@ -9497,12 +9393,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
clone: 1.0.4
|
clone: 1.0.4
|
||||||
|
|
||||||
define-data-property@1.1.4:
|
|
||||||
dependencies:
|
|
||||||
es-define-property: 1.0.1
|
|
||||||
es-errors: 1.3.0
|
|
||||||
gopd: 1.2.0
|
|
||||||
|
|
||||||
define-lazy-prop@3.0.0: {}
|
define-lazy-prop@3.0.0: {}
|
||||||
|
|
||||||
delayed-stream@1.0.0: {}
|
delayed-stream@1.0.0: {}
|
||||||
@ -9970,10 +9860,6 @@ snapshots:
|
|||||||
locate-path: 7.2.0
|
locate-path: 7.2.0
|
||||||
path-exists: 5.0.0
|
path-exists: 5.0.0
|
||||||
|
|
||||||
find-yarn-workspace-root@2.0.0:
|
|
||||||
dependencies:
|
|
||||||
micromatch: 4.0.8
|
|
||||||
|
|
||||||
flat-cache@4.0.1:
|
flat-cache@4.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
flatted: 3.3.3
|
flatted: 3.3.3
|
||||||
@ -10007,13 +9893,6 @@ snapshots:
|
|||||||
fs-constants@1.0.0:
|
fs-constants@1.0.0:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
fs-extra@9.1.0:
|
|
||||||
dependencies:
|
|
||||||
at-least-node: 1.0.0
|
|
||||||
graceful-fs: 4.2.11
|
|
||||||
jsonfile: 6.1.0
|
|
||||||
universalify: 2.0.1
|
|
||||||
|
|
||||||
fs-minipass@2.1.0:
|
fs-minipass@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
minipass: 3.3.6
|
minipass: 3.3.6
|
||||||
@ -10038,19 +9917,6 @@ snapshots:
|
|||||||
|
|
||||||
get-east-asian-width@1.3.0: {}
|
get-east-asian-width@1.3.0: {}
|
||||||
|
|
||||||
get-intrinsic@1.2.7:
|
|
||||||
dependencies:
|
|
||||||
call-bind-apply-helpers: 1.0.1
|
|
||||||
es-define-property: 1.0.1
|
|
||||||
es-errors: 1.3.0
|
|
||||||
es-object-atoms: 1.1.1
|
|
||||||
function-bind: 1.1.2
|
|
||||||
get-proto: 1.0.1
|
|
||||||
gopd: 1.2.0
|
|
||||||
has-symbols: 1.1.0
|
|
||||||
hasown: 2.0.2
|
|
||||||
math-intrinsics: 1.1.0
|
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@ -10127,10 +9993,6 @@ snapshots:
|
|||||||
|
|
||||||
has-flag@4.0.0: {}
|
has-flag@4.0.0: {}
|
||||||
|
|
||||||
has-property-descriptors@1.0.2:
|
|
||||||
dependencies:
|
|
||||||
es-define-property: 1.0.1
|
|
||||||
|
|
||||||
has-symbols@1.1.0: {}
|
has-symbols@1.1.0: {}
|
||||||
|
|
||||||
hasown@2.0.2:
|
hasown@2.0.2:
|
||||||
@ -10320,8 +10182,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
|
|
||||||
is-docker@2.2.1: {}
|
|
||||||
|
|
||||||
is-docker@3.0.0: {}
|
is-docker@3.0.0: {}
|
||||||
|
|
||||||
is-extglob@2.1.1: {}
|
is-extglob@2.1.1: {}
|
||||||
@ -10366,18 +10226,12 @@ snapshots:
|
|||||||
|
|
||||||
is-what@3.14.1: {}
|
is-what@3.14.1: {}
|
||||||
|
|
||||||
is-wsl@2.2.0:
|
|
||||||
dependencies:
|
|
||||||
is-docker: 2.2.1
|
|
||||||
|
|
||||||
is-wsl@3.1.0:
|
is-wsl@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-inside-container: 1.0.0
|
is-inside-container: 1.0.0
|
||||||
|
|
||||||
isarray@1.0.0: {}
|
isarray@1.0.0: {}
|
||||||
|
|
||||||
isarray@2.0.5: {}
|
|
||||||
|
|
||||||
isexe@2.0.0: {}
|
isexe@2.0.0: {}
|
||||||
|
|
||||||
isexe@3.1.1: {}
|
isexe@3.1.1: {}
|
||||||
@ -10896,25 +10750,10 @@ snapshots:
|
|||||||
|
|
||||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||||
|
|
||||||
json-stable-stringify@1.1.0:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
isarray: 2.0.5
|
|
||||||
jsonify: 0.0.1
|
|
||||||
object-keys: 1.1.1
|
|
||||||
|
|
||||||
json5@2.2.3: {}
|
json5@2.2.3: {}
|
||||||
|
|
||||||
jsonc-parser@3.3.1: {}
|
jsonc-parser@3.3.1: {}
|
||||||
|
|
||||||
jsonfile@6.1.0:
|
|
||||||
dependencies:
|
|
||||||
universalify: 2.0.1
|
|
||||||
optionalDependencies:
|
|
||||||
graceful-fs: 4.2.11
|
|
||||||
|
|
||||||
jsonify@0.0.1: {}
|
|
||||||
|
|
||||||
jsonparse@1.3.1: {}
|
jsonparse@1.3.1: {}
|
||||||
|
|
||||||
karma-source-map-support@1.4.0:
|
karma-source-map-support@1.4.0:
|
||||||
@ -10927,10 +10766,6 @@ snapshots:
|
|||||||
|
|
||||||
kind-of@6.0.3: {}
|
kind-of@6.0.3: {}
|
||||||
|
|
||||||
klaw-sync@6.0.0:
|
|
||||||
dependencies:
|
|
||||||
graceful-fs: 4.2.11
|
|
||||||
|
|
||||||
kleur@3.0.3: {}
|
kleur@3.0.3: {}
|
||||||
|
|
||||||
launch-editor@2.10.0:
|
launch-editor@2.10.0:
|
||||||
@ -11289,12 +11124,6 @@ snapshots:
|
|||||||
'@angular/core': 19.2.9(rxjs@7.8.2)(zone.js@0.15.0)
|
'@angular/core': 19.2.9(rxjs@7.8.2)(zone.js@0.15.0)
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
ngx-file-drop@16.0.0(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0)):
|
|
||||||
dependencies:
|
|
||||||
'@angular/common': 19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
|
|
||||||
'@angular/core': 19.2.9(rxjs@7.8.2)(zone.js@0.15.0)
|
|
||||||
tslib: 2.8.1
|
|
||||||
|
|
||||||
ngx-ui-tour-core@14.0.0(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(@angular/router@19.2.9(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@19.2.9(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2))(rxjs@7.8.2):
|
ngx-ui-tour-core@14.0.0(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(@angular/router@19.2.9(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(@angular/platform-browser@19.2.9(@angular/common@19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2))(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0)))(rxjs@7.8.2))(rxjs@7.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@angular/common': 19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
|
'@angular/common': 19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
|
||||||
@ -11303,7 +11132,7 @@ snapshots:
|
|||||||
rxjs: 7.8.2
|
rxjs: 7.8.2
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
ngx-ui-tour-ng-bootstrap@16.0.0(nfyq54qpjcnpjhdwpvrgi4nyra):
|
ngx-ui-tour-ng-bootstrap@16.0.0(9bfbf45bdfd1029869b23707ee6bb312):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@angular/common': 19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
|
'@angular/common': 19.2.9(@angular/core@19.2.9(rxjs@7.8.2)(zone.js@0.15.0))(rxjs@7.8.2)
|
||||||
'@angular/core': 19.2.9(rxjs@7.8.2)(zone.js@0.15.0)
|
'@angular/core': 19.2.9(rxjs@7.8.2)(zone.js@0.15.0)
|
||||||
@ -11412,8 +11241,6 @@ snapshots:
|
|||||||
|
|
||||||
object-inspect@1.13.4: {}
|
object-inspect@1.13.4: {}
|
||||||
|
|
||||||
object-keys@1.1.1: {}
|
|
||||||
|
|
||||||
obuf@1.1.2: {}
|
obuf@1.1.2: {}
|
||||||
|
|
||||||
on-finished@2.4.1:
|
on-finished@2.4.1:
|
||||||
@ -11441,11 +11268,6 @@ snapshots:
|
|||||||
is-inside-container: 1.0.0
|
is-inside-container: 1.0.0
|
||||||
is-wsl: 3.1.0
|
is-wsl: 3.1.0
|
||||||
|
|
||||||
open@7.4.2:
|
|
||||||
dependencies:
|
|
||||||
is-docker: 2.2.1
|
|
||||||
is-wsl: 2.2.0
|
|
||||||
|
|
||||||
optionator@0.9.4:
|
optionator@0.9.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
deep-is: 0.1.4
|
deep-is: 0.1.4
|
||||||
@ -11561,24 +11383,6 @@ snapshots:
|
|||||||
|
|
||||||
parseurl@1.3.3: {}
|
parseurl@1.3.3: {}
|
||||||
|
|
||||||
patch-package@8.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@yarnpkg/lockfile': 1.1.0
|
|
||||||
chalk: 4.1.2
|
|
||||||
ci-info: 3.9.0
|
|
||||||
cross-spawn: 7.0.6
|
|
||||||
find-yarn-workspace-root: 2.0.0
|
|
||||||
fs-extra: 9.1.0
|
|
||||||
json-stable-stringify: 1.1.0
|
|
||||||
klaw-sync: 6.0.0
|
|
||||||
minimist: 1.2.8
|
|
||||||
open: 7.4.2
|
|
||||||
rimraf: 2.7.1
|
|
||||||
semver: 7.7.1
|
|
||||||
slash: 2.0.0
|
|
||||||
tmp: 0.0.33
|
|
||||||
yaml: 2.7.0
|
|
||||||
|
|
||||||
path-exists@4.0.0: {}
|
path-exists@4.0.0: {}
|
||||||
|
|
||||||
path-exists@5.0.0: {}
|
path-exists@5.0.0: {}
|
||||||
@ -11883,10 +11687,6 @@ snapshots:
|
|||||||
|
|
||||||
rfdc@1.4.1: {}
|
rfdc@1.4.1: {}
|
||||||
|
|
||||||
rimraf@2.7.1:
|
|
||||||
dependencies:
|
|
||||||
glob: 7.2.3
|
|
||||||
|
|
||||||
rollup@4.34.8:
|
rollup@4.34.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree': 1.0.6
|
'@types/estree': 1.0.6
|
||||||
@ -12018,15 +11818,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
set-function-length@1.2.1:
|
|
||||||
dependencies:
|
|
||||||
define-data-property: 1.1.4
|
|
||||||
es-errors: 1.3.0
|
|
||||||
function-bind: 1.1.2
|
|
||||||
get-intrinsic: 1.2.7
|
|
||||||
gopd: 1.2.0
|
|
||||||
has-property-descriptors: 1.0.2
|
|
||||||
|
|
||||||
setprototypeof@1.1.0: {}
|
setprototypeof@1.1.0: {}
|
||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
@ -12105,8 +11896,6 @@ snapshots:
|
|||||||
|
|
||||||
sisteransi@1.0.5: {}
|
sisteransi@1.0.5: {}
|
||||||
|
|
||||||
slash@2.0.0: {}
|
|
||||||
|
|
||||||
slash@3.0.0: {}
|
slash@3.0.0: {}
|
||||||
|
|
||||||
slash@5.1.0: {}
|
slash@5.1.0: {}
|
||||||
@ -12517,8 +12306,6 @@ snapshots:
|
|||||||
|
|
||||||
universalify@0.2.0: {}
|
universalify@0.2.0: {}
|
||||||
|
|
||||||
universalify@2.0.1: {}
|
|
||||||
|
|
||||||
unpipe@1.0.0: {}
|
unpipe@1.0.0: {}
|
||||||
|
|
||||||
unplugin@1.16.1:
|
unplugin@1.16.1:
|
||||||
@ -12783,7 +12570,8 @@ snapshots:
|
|||||||
|
|
||||||
yallist@5.0.0: {}
|
yallist@5.0.0: {}
|
||||||
|
|
||||||
yaml@2.7.0: {}
|
yaml@2.7.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
yargs-parser@21.1.1: {}
|
yargs-parser@21.1.1: {}
|
||||||
|
|
||||||
|
@ -121,19 +121,4 @@ HTMLCanvasElement.prototype.getContext = <
|
|||||||
typeof HTMLCanvasElement.prototype.getContext
|
typeof HTMLCanvasElement.prototype.getContext
|
||||||
>jest.fn()
|
>jest.fn()
|
||||||
|
|
||||||
// pdfjs
|
jest.mock('pdfjs-dist')
|
||||||
jest.mock('pdfjs-dist', () => ({
|
|
||||||
getDocument: jest.fn(() => ({
|
|
||||||
promise: Promise.resolve({ numPages: 3 }),
|
|
||||||
})),
|
|
||||||
GlobalWorkerOptions: { workerSrc: '' },
|
|
||||||
VerbosityLevel: { ERRORS: 0 },
|
|
||||||
globalThis: {
|
|
||||||
pdfjsLib: {
|
|
||||||
GlobalWorkerOptions: {
|
|
||||||
workerSrc: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
jest.mock('pdfjs-dist/web/pdf_viewer', () => ({}))
|
|
||||||
|
@ -9,7 +9,6 @@ import {
|
|||||||
import { Router, RouterModule } from '@angular/router'
|
import { Router, RouterModule } from '@angular/router'
|
||||||
import { NgbModalModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModalModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { allIcons, NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
import { allIcons, NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||||
import { NgxFileDropModule } from 'ngx-file-drop'
|
|
||||||
import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap'
|
import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap'
|
||||||
import { Subject } from 'rxjs'
|
import { Subject } from 'rxjs'
|
||||||
import { routes } from './app-routing.module'
|
import { routes } from './app-routing.module'
|
||||||
@ -43,7 +42,6 @@ describe('AppComponent', () => {
|
|||||||
imports: [
|
imports: [
|
||||||
TourNgBootstrapModule,
|
TourNgBootstrapModule,
|
||||||
RouterModule.forRoot(routes),
|
RouterModule.forRoot(routes),
|
||||||
NgxFileDropModule,
|
|
||||||
NgbModalModule,
|
NgbModalModule,
|
||||||
AppComponent,
|
AppComponent,
|
||||||
ToastsComponent,
|
ToastsComponent,
|
||||||
|
@ -105,9 +105,9 @@ describe('ConfigComponent', () => {
|
|||||||
|
|
||||||
it('should support JSON validation for e.g. user_args', () => {
|
it('should support JSON validation for e.g. user_args', () => {
|
||||||
component.configForm.patchValue({ user_args: '{ foo bar }' })
|
component.configForm.patchValue({ user_args: '{ foo bar }' })
|
||||||
expect(component.errors).toEqual({ user_args: 'Invalid JSON' })
|
expect(component.errors['user_args']).toEqual('Invalid JSON')
|
||||||
component.configForm.patchValue({ user_args: '{ "foo": "bar" }' })
|
component.configForm.patchValue({ user_args: '{ "foo": "bar" }' })
|
||||||
expect(component.errors).toEqual({ user_args: null })
|
expect(component.errors['user_args']).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should upload file, show error if necessary', () => {
|
it('should upload file, show error if necessary', () => {
|
||||||
|
@ -123,7 +123,15 @@
|
|||||||
<p class="small" i18n>Set scheduled trigger offset and which date field to use.</p>
|
<p class="small" i18n>Set scheduled trigger offset and which date field to use.</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<pngx-input-number i18n-title title="Offset days" formControlName="schedule_offset_days" [showAdd]="false" [error]="error?.schedule_offset_days"></pngx-input-number>
|
<pngx-input-number
|
||||||
|
i18n-title
|
||||||
|
title="Offset days"
|
||||||
|
formControlName="schedule_offset_days"
|
||||||
|
[showAdd]="false"
|
||||||
|
[error]="error?.schedule_offset_days"
|
||||||
|
hint="Positive values will trigger the workflow before the date, negative values after."
|
||||||
|
i18n-hint
|
||||||
|
></pngx-input-number>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<pngx-input-select i18n-title title="Relative to" formControlName="schedule_date_field" [items]="scheduleDateFieldOptions" [error]="error?.schedule_date_field"></pngx-input-select>
|
<pngx-input-select i18n-title title="Relative to" formControlName="schedule_date_field" [items]="scheduleDateFieldOptions" [error]="error?.schedule_date_field"></pngx-input-select>
|
||||||
|
@ -82,10 +82,20 @@ describe('UploadFileWidgetComponent', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should upload files', () => {
|
it('should upload files', () => {
|
||||||
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFiles')
|
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFile')
|
||||||
fixture.debugElement
|
const file = new File(
|
||||||
.query(By.css('input'))
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
.nativeElement.dispatchEvent(new Event('change'))
|
'file.pdf'
|
||||||
|
)
|
||||||
|
const fileInput = fixture.debugElement.query(By.css('input'))
|
||||||
|
jest.spyOn(fileInput.nativeElement, 'files', 'get').mockReturnValue({
|
||||||
|
item: () => file,
|
||||||
|
length: 1,
|
||||||
|
[Symbol.iterator]: () => ({
|
||||||
|
next: () => ({ done: false, value: file }),
|
||||||
|
}),
|
||||||
|
} as any)
|
||||||
|
fileInput.nativeElement.dispatchEvent(new Event('change'))
|
||||||
expect(uploadSpy).toHaveBeenCalled()
|
expect(uploadSpy).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -134,9 +134,11 @@ export class UploadFileWidgetComponent extends ComponentWithPermissions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onFileSelected(event: Event) {
|
public onFileSelected(event: Event) {
|
||||||
this.uploadDocumentsService.uploadFiles(
|
const files = (event.target as HTMLInputElement).files
|
||||||
(event.target as HTMLInputElement).files
|
for (let i = 0; i < files?.length; i++) {
|
||||||
)
|
const file = files.item(i)
|
||||||
|
file && this.uploadDocumentsService.uploadFile(file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get slimSidebarEnabled(): boolean {
|
get slimSidebarEnabled(): boolean {
|
||||||
|
@ -2,13 +2,6 @@
|
|||||||
<ng-content select="[content]"></ng-content>
|
<ng-content select="[content]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="global-dropzone-overlay position-fixed top-0 start-0 bottom-0 end-0 text-center pe-none fade" [class.show]="fileIsOver" [class.hide]="hidden">
|
<div class="global-dropzone-overlay position-fixed top-0 start-0 bottom-0 end-0 text-center pe-none" [class.active]="fileIsOver && !hidden">
|
||||||
<h2 class="pe-none position-absolute top-50 start-50 translate-middle" i18n>Drop files to begin upload</h2>
|
<h2 class="pe-none position-absolute top-50 start-50 translate-middle" i18n>Drop files to begin upload</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ngx-file-drop
|
|
||||||
dropZoneClassName="visually-hidden"
|
|
||||||
contentClassName="visually-hidden"
|
|
||||||
(onFileDrop)="dropped($event)"
|
|
||||||
#ngxFileDrop>
|
|
||||||
</ngx-file-drop>
|
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
.global-dropzone-overlay {
|
.global-dropzone-overlay {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.25s ease-in-out;
|
||||||
background-color: hsla(var(--pngx-primary), var(--pngx-primary-lightness), .8);
|
background-color: hsla(var(--pngx-primary), var(--pngx-primary-lightness), .8);
|
||||||
z-index: 1200;
|
z-index: 1200;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
color: var(--pngx-primary-text-contrast)
|
color: var(--pngx-primary-text-contrast)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import {
|
|||||||
tick,
|
tick,
|
||||||
} from '@angular/core/testing'
|
} from '@angular/core/testing'
|
||||||
import { By } from '@angular/platform-browser'
|
import { By } from '@angular/platform-browser'
|
||||||
import { NgxFileDropEntry, NgxFileDropModule } from 'ngx-file-drop'
|
|
||||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||||
import { SettingsService } from 'src/app/services/settings.service'
|
import { SettingsService } from 'src/app/services/settings.service'
|
||||||
import { ToastService } from 'src/app/services/toast.service'
|
import { ToastService } from 'src/app/services/toast.service'
|
||||||
@ -27,7 +26,7 @@ describe('FileDropComponent', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [NgxFileDropModule, FileDropComponent, ToastsComponent],
|
imports: [FileDropComponent, ToastsComponent],
|
||||||
providers: [
|
providers: [
|
||||||
provideHttpClient(withInterceptorsFromDi()),
|
provideHttpClient(withInterceptorsFromDi()),
|
||||||
provideHttpClientTesting(),
|
provideHttpClientTesting(),
|
||||||
@ -66,12 +65,12 @@ describe('FileDropComponent', () => {
|
|||||||
const dropzone = fixture.debugElement.query(
|
const dropzone = fixture.debugElement.query(
|
||||||
By.css('.global-dropzone-overlay')
|
By.css('.global-dropzone-overlay')
|
||||||
)
|
)
|
||||||
expect(dropzone.classes['hide']).toBeTruthy()
|
expect(dropzone.classes['active']).toBeFalsy()
|
||||||
component.onDragLeave(new Event('dragleave') as DragEvent)
|
component.onDragLeave(new Event('dragleave') as DragEvent)
|
||||||
tick(700)
|
tick(700)
|
||||||
fixture.detectChanges()
|
fixture.detectChanges()
|
||||||
// drop
|
// drop
|
||||||
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFiles')
|
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFile')
|
||||||
const dragEvent = new Event('drop')
|
const dragEvent = new Event('drop')
|
||||||
dragEvent['dataTransfer'] = {
|
dragEvent['dataTransfer'] = {
|
||||||
files: {
|
files: {
|
||||||
@ -93,53 +92,209 @@ describe('FileDropComponent', () => {
|
|||||||
tick(1)
|
tick(1)
|
||||||
fixture.detectChanges()
|
fixture.detectChanges()
|
||||||
expect(component.fileIsOver).toBeTruthy()
|
expect(component.fileIsOver).toBeTruthy()
|
||||||
const dropzone = fixture.debugElement.query(
|
|
||||||
By.css('.global-dropzone-overlay')
|
|
||||||
)
|
|
||||||
component.onDragLeave(new Event('dragleave') as DragEvent)
|
component.onDragLeave(new Event('dragleave') as DragEvent)
|
||||||
tick(700)
|
tick(700)
|
||||||
fixture.detectChanges()
|
fixture.detectChanges()
|
||||||
expect(dropzone.classes['hide']).toBeTruthy()
|
|
||||||
// drop
|
// drop
|
||||||
const toastSpy = jest.spyOn(toastService, 'show')
|
const toastSpy = jest.spyOn(toastService, 'show')
|
||||||
const uploadSpy = jest.spyOn(
|
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFile')
|
||||||
UploadDocumentsService.prototype as any,
|
const file = new File(
|
||||||
'uploadFile'
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
|
'file.pdf'
|
||||||
)
|
)
|
||||||
const dragEvent = new Event('drop')
|
const dragEvent = new Event('drop')
|
||||||
dragEvent['dataTransfer'] = {
|
dragEvent['dataTransfer'] = {
|
||||||
files: {
|
items: [
|
||||||
item: () => {
|
{
|
||||||
return new File(
|
kind: 'file',
|
||||||
[new Blob(['testing'], { type: 'application/pdf' })],
|
type: 'application/pdf',
|
||||||
'file.pdf'
|
getAsFile: () => file,
|
||||||
)
|
|
||||||
},
|
},
|
||||||
length: 1,
|
],
|
||||||
} as unknown as FileList,
|
|
||||||
}
|
}
|
||||||
component.onDrop(dragEvent as DragEvent)
|
component.onDrop(dragEvent as DragEvent)
|
||||||
component.dropped([
|
|
||||||
{
|
|
||||||
fileEntry: {
|
|
||||||
isFile: true,
|
|
||||||
file: (callback) => {
|
|
||||||
callback(
|
|
||||||
new File(
|
|
||||||
[new Blob(['testing'], { type: 'application/pdf' })],
|
|
||||||
'file.pdf'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as unknown as NgxFileDropEntry,
|
|
||||||
])
|
|
||||||
tick(3000)
|
tick(3000)
|
||||||
expect(toastSpy).toHaveBeenCalled()
|
expect(toastSpy).toHaveBeenCalled()
|
||||||
expect(uploadSpy).toHaveBeenCalled()
|
expect(uploadSpy).toHaveBeenCalled()
|
||||||
discardPeriodicTasks()
|
discardPeriodicTasks()
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
it('should support drag drop, initiate upload with webkitGetAsEntry', fakeAsync(() => {
|
||||||
|
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||||
|
expect(component.fileIsOver).toBeFalsy()
|
||||||
|
const overEvent = new Event('dragover') as DragEvent
|
||||||
|
;(overEvent as any).dataTransfer = { types: ['Files'] }
|
||||||
|
component.onDragOver(overEvent)
|
||||||
|
tick(1)
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(component.fileIsOver).toBeTruthy()
|
||||||
|
component.onDragLeave(new Event('dragleave') as DragEvent)
|
||||||
|
tick(700)
|
||||||
|
fixture.detectChanges()
|
||||||
|
// drop
|
||||||
|
const toastSpy = jest.spyOn(toastService, 'show')
|
||||||
|
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFile')
|
||||||
|
const file = new File(
|
||||||
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
|
'file.pdf'
|
||||||
|
)
|
||||||
|
const dragEvent = new Event('drop')
|
||||||
|
dragEvent['dataTransfer'] = {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
kind: 'file',
|
||||||
|
type: 'application/pdf',
|
||||||
|
webkitGetAsEntry: () => ({
|
||||||
|
isFile: true,
|
||||||
|
isDirectory: false,
|
||||||
|
file: (cb: (file: File) => void) => cb(file),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
files: [],
|
||||||
|
}
|
||||||
|
component.onDrop(dragEvent as DragEvent)
|
||||||
|
tick(3000)
|
||||||
|
expect(toastSpy).toHaveBeenCalled()
|
||||||
|
expect(uploadSpy).toHaveBeenCalled()
|
||||||
|
discardPeriodicTasks()
|
||||||
|
}))
|
||||||
|
|
||||||
|
it('should show an error on traverseFileTree error', fakeAsync(() => {
|
||||||
|
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||||
|
const toastSpy = jest.spyOn(toastService, 'showError')
|
||||||
|
const traverseSpy = jest
|
||||||
|
.spyOn(component as any, 'traverseFileTree')
|
||||||
|
.mockReturnValue(Promise.reject(new Error('Error traversing file tree')))
|
||||||
|
fixture.detectChanges()
|
||||||
|
|
||||||
|
// Simulate a drop with a directory entry
|
||||||
|
const mockEntry = {
|
||||||
|
isDirectory: true,
|
||||||
|
isFile: false,
|
||||||
|
createReader: () => ({ readEntries: jest.fn() }),
|
||||||
|
} as unknown as FileSystemDirectoryEntry
|
||||||
|
|
||||||
|
const event = {
|
||||||
|
preventDefault: () => {},
|
||||||
|
stopImmediatePropagation: () => {},
|
||||||
|
dataTransfer: {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
kind: 'file',
|
||||||
|
webkitGetAsEntry: () => mockEntry,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
} as unknown as DragEvent
|
||||||
|
|
||||||
|
component.onDrop(event)
|
||||||
|
|
||||||
|
tick() // flush microtasks (e.g., Promise.reject)
|
||||||
|
|
||||||
|
expect(traverseSpy).toHaveBeenCalled()
|
||||||
|
expect(toastSpy).toHaveBeenCalledWith(
|
||||||
|
$localize`Failed to read dropped items: Error traversing file tree`
|
||||||
|
)
|
||||||
|
|
||||||
|
discardPeriodicTasks()
|
||||||
|
}))
|
||||||
|
|
||||||
|
it('should support drag drop, initiate upload without DataTransfer API support', fakeAsync(() => {
|
||||||
|
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||||
|
expect(component.fileIsOver).toBeFalsy()
|
||||||
|
const overEvent = new Event('dragover') as DragEvent
|
||||||
|
;(overEvent as any).dataTransfer = { types: ['Files'] }
|
||||||
|
component.onDragOver(overEvent)
|
||||||
|
tick(1)
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(component.fileIsOver).toBeTruthy()
|
||||||
|
component.onDragLeave(new Event('dragleave') as DragEvent)
|
||||||
|
tick(700)
|
||||||
|
fixture.detectChanges()
|
||||||
|
// drop
|
||||||
|
const toastSpy = jest.spyOn(toastService, 'show')
|
||||||
|
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFile')
|
||||||
|
const file = new File(
|
||||||
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
|
'file.pdf'
|
||||||
|
)
|
||||||
|
const dragEvent = new Event('drop')
|
||||||
|
dragEvent['dataTransfer'] = {
|
||||||
|
items: [],
|
||||||
|
files: [file],
|
||||||
|
}
|
||||||
|
component.onDrop(dragEvent as DragEvent)
|
||||||
|
tick(3000)
|
||||||
|
expect(toastSpy).toHaveBeenCalled()
|
||||||
|
expect(uploadSpy).toHaveBeenCalled()
|
||||||
|
discardPeriodicTasks()
|
||||||
|
}))
|
||||||
|
|
||||||
|
it('should resolve a single file when entry isFile', () => {
|
||||||
|
const mockFile = new File(['data'], 'test.txt', { type: 'text/plain' })
|
||||||
|
const mockEntry = {
|
||||||
|
isFile: true,
|
||||||
|
isDirectory: false,
|
||||||
|
file: (cb: (f: File) => void) => cb(mockFile),
|
||||||
|
} as unknown as FileSystemFileEntry
|
||||||
|
|
||||||
|
return (component as any)
|
||||||
|
.traverseFileTree(mockEntry)
|
||||||
|
.then((result: File[]) => {
|
||||||
|
expect(result).toEqual([mockFile])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should resolve all files in a flat directory', async () => {
|
||||||
|
const file1 = new File(['data'], 'file1.txt')
|
||||||
|
const file2 = new File(['data'], 'file2.txt')
|
||||||
|
|
||||||
|
const mockFileEntry1 = {
|
||||||
|
isFile: true,
|
||||||
|
isDirectory: false,
|
||||||
|
file: (cb: (f: File) => void) => cb(file1),
|
||||||
|
} as unknown as FileSystemFileEntry
|
||||||
|
|
||||||
|
const mockFileEntry2 = {
|
||||||
|
isFile: true,
|
||||||
|
isDirectory: false,
|
||||||
|
file: (cb: (f: File) => void) => cb(file2),
|
||||||
|
} as unknown as FileSystemFileEntry
|
||||||
|
|
||||||
|
let callCount = 0
|
||||||
|
|
||||||
|
const mockDirEntry = {
|
||||||
|
isFile: false,
|
||||||
|
isDirectory: true,
|
||||||
|
createReader: () => ({
|
||||||
|
readEntries: (cb: (batch: FileSystemEntry[]) => void) => {
|
||||||
|
if (callCount++ === 0) {
|
||||||
|
cb([mockFileEntry1, mockFileEntry2])
|
||||||
|
} else {
|
||||||
|
cb([]) // second call: signal EOF
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
} as unknown as FileSystemDirectoryEntry
|
||||||
|
|
||||||
|
const result = await (component as any).traverseFileTree(mockDirEntry)
|
||||||
|
expect(result).toEqual([file1, file2])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should resolve a non-file non-directory entry as an empty array', () => {
|
||||||
|
const mockEntry = {
|
||||||
|
isFile: false,
|
||||||
|
isDirectory: false,
|
||||||
|
file: (cb: (f: File) => void) => cb(new File([], '')),
|
||||||
|
} as unknown as FileSystemEntry
|
||||||
|
return (component as any)
|
||||||
|
.traverseFileTree(mockEntry)
|
||||||
|
.then((result: File[]) => {
|
||||||
|
expect(result).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should ignore events if disabled', fakeAsync(() => {
|
it('should ignore events if disabled', fakeAsync(() => {
|
||||||
settingsService.globalDropzoneEnabled = false
|
settingsService.globalDropzoneEnabled = false
|
||||||
expect(settingsService.globalDropzoneActive).toBeFalsy()
|
expect(settingsService.globalDropzoneActive).toBeFalsy()
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
import { Component, HostListener, ViewChild } from '@angular/core'
|
import { Component, HostListener } from '@angular/core'
|
||||||
import {
|
|
||||||
NgxFileDropComponent,
|
|
||||||
NgxFileDropEntry,
|
|
||||||
NgxFileDropModule,
|
|
||||||
} from 'ngx-file-drop'
|
|
||||||
import {
|
import {
|
||||||
PermissionAction,
|
PermissionAction,
|
||||||
PermissionsService,
|
PermissionsService,
|
||||||
@ -17,7 +12,7 @@ import { UploadDocumentsService } from 'src/app/services/upload-documents.servic
|
|||||||
selector: 'pngx-file-drop',
|
selector: 'pngx-file-drop',
|
||||||
templateUrl: './file-drop.component.html',
|
templateUrl: './file-drop.component.html',
|
||||||
styleUrls: ['./file-drop.component.scss'],
|
styleUrls: ['./file-drop.component.scss'],
|
||||||
imports: [NgxFileDropModule],
|
imports: [],
|
||||||
})
|
})
|
||||||
export class FileDropComponent {
|
export class FileDropComponent {
|
||||||
private fileLeaveTimeoutID: any
|
private fileLeaveTimeoutID: any
|
||||||
@ -41,8 +36,6 @@ export class FileDropComponent {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewChild('ngxFileDrop') ngxFileDrop: NgxFileDropComponent
|
|
||||||
|
|
||||||
@HostListener('document:dragover', ['$event']) onDragOver(event: DragEvent) {
|
@HostListener('document:dragover', ['$event']) onDragOver(event: DragEvent) {
|
||||||
if (!this.dragDropEnabled || !event.dataTransfer?.types?.includes('Files'))
|
if (!this.dragDropEnabled || !event.dataTransfer?.types?.includes('Files'))
|
||||||
return
|
return
|
||||||
@ -78,19 +71,85 @@ export class FileDropComponent {
|
|||||||
}, ms)
|
}, ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private traverseFileTree(entry: FileSystemEntry): Promise<File[]> {
|
||||||
|
if (entry.isFile) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
;(entry as FileSystemFileEntry).file(resolve, reject)
|
||||||
|
}).then((file: File) => [file])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.isDirectory) {
|
||||||
|
return new Promise<File[]>((resolve, reject) => {
|
||||||
|
const dirReader = (entry as FileSystemDirectoryEntry).createReader()
|
||||||
|
const allEntries: FileSystemEntry[] = []
|
||||||
|
|
||||||
|
const readEntries = () => {
|
||||||
|
dirReader.readEntries((batch) => {
|
||||||
|
if (batch.length === 0) {
|
||||||
|
const promises = allEntries.map((child) =>
|
||||||
|
this.traverseFileTree(child)
|
||||||
|
)
|
||||||
|
Promise.all(promises)
|
||||||
|
.then((results) => resolve([].concat(...results)))
|
||||||
|
.catch(reject)
|
||||||
|
} else {
|
||||||
|
allEntries.push(...batch)
|
||||||
|
readEntries() // keep reading
|
||||||
|
}
|
||||||
|
}, reject)
|
||||||
|
}
|
||||||
|
|
||||||
|
readEntries()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve([])
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('document:drop', ['$event']) public onDrop(event: DragEvent) {
|
@HostListener('document:drop', ['$event']) public onDrop(event: DragEvent) {
|
||||||
if (!this.dragDropEnabled) return
|
if (!this.dragDropEnabled) return
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopImmediatePropagation()
|
event.stopImmediatePropagation()
|
||||||
// pass event onto ngx-file-drop to handle files
|
|
||||||
this.ngxFileDrop.dropFiles(event)
|
|
||||||
this.onDragLeave(event, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
public dropped(files: NgxFileDropEntry[]) {
|
const files: File[] = []
|
||||||
this.uploadDocumentsService.onNgxFileDrop(files)
|
const entries: FileSystemEntry[] = []
|
||||||
if (files.length > 0)
|
if (event.dataTransfer?.items && event.dataTransfer.items.length) {
|
||||||
|
for (const item of Array.from(event.dataTransfer.items)) {
|
||||||
|
if (item.webkitGetAsEntry) {
|
||||||
|
// webkitGetAsEntry not standard, but is widely supported
|
||||||
|
const entry = item.webkitGetAsEntry()
|
||||||
|
if (entry) entries.push(entry)
|
||||||
|
} else if (item.kind === 'file') {
|
||||||
|
const file = item.getAsFile()
|
||||||
|
if (file) files.push(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event.dataTransfer?.files) {
|
||||||
|
// Fallback for browsers without DataTransferItem API
|
||||||
|
for (const file of Array.from(event.dataTransfer.files)) {
|
||||||
|
files.push(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.length) {
|
||||||
|
const promises = entries.map((entry) => this.traverseFileTree(entry))
|
||||||
|
Promise.all(promises)
|
||||||
|
.then((results) => {
|
||||||
|
files.push(...[].concat(...results))
|
||||||
|
this.toastService.showInfo($localize`Initiating upload...`, 3000)
|
||||||
|
files.forEach((file) => this.uploadDocumentsService.uploadFile(file))
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
this.toastService.showError(
|
||||||
|
$localize`Failed to read dropped items: ${e.message}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else if (files.length) {
|
||||||
this.toastService.showInfo($localize`Initiating upload...`, 3000)
|
this.toastService.showInfo($localize`Initiating upload...`, 3000)
|
||||||
|
files.forEach((file) => this.uploadDocumentsService.uploadFile(file))
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onDragLeave(event, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:blur', ['$event']) public onWindowBlur() {
|
@HostListener('window:blur', ['$event']) public onWindowBlur() {
|
||||||
|
@ -49,6 +49,7 @@ export enum ConfigOptionType {
|
|||||||
export const ConfigCategory = {
|
export const ConfigCategory = {
|
||||||
General: $localize`General Settings`,
|
General: $localize`General Settings`,
|
||||||
OCR: $localize`OCR Settings`,
|
OCR: $localize`OCR Settings`,
|
||||||
|
Barcode: $localize`Barcode Settings`,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigOption {
|
export interface ConfigOption {
|
||||||
@ -180,6 +181,83 @@ export const PaperlessConfigOptions: ConfigOption[] = [
|
|||||||
config_key: 'PAPERLESS_APP_TITLE',
|
config_key: 'PAPERLESS_APP_TITLE',
|
||||||
category: ConfigCategory.General,
|
category: ConfigCategory.General,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'barcodes_enabled',
|
||||||
|
title: $localize`Enable Barcodes`,
|
||||||
|
type: ConfigOptionType.Boolean,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_ENABLE_BARCODES',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_enable_tiff_support',
|
||||||
|
title: $localize`Enable TIFF Support`,
|
||||||
|
type: ConfigOptionType.Boolean,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_BARCODE_TIFF_SUPPORT',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_string',
|
||||||
|
title: $localize`Barcode String`,
|
||||||
|
type: ConfigOptionType.String,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_BARCODE_STRING',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_retain_split_pages',
|
||||||
|
title: $localize`Retain Split Pages`,
|
||||||
|
type: ConfigOptionType.Boolean,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_BARCODE_RETAIN_SPLIT_PAGES',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_enable_asn',
|
||||||
|
title: $localize`Enable ASN`,
|
||||||
|
type: ConfigOptionType.Boolean,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_asn_prefix',
|
||||||
|
title: $localize`ASN Prefix`,
|
||||||
|
type: ConfigOptionType.String,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_ASN_BARCODE_PREFIX',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_upscale',
|
||||||
|
title: $localize`Upscale`,
|
||||||
|
type: ConfigOptionType.Number,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_BARCODE_UPSCALE',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_dpi',
|
||||||
|
title: $localize`DPI`,
|
||||||
|
type: ConfigOptionType.Number,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_BARCODE_DPI',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_max_pages',
|
||||||
|
title: $localize`Max Pages`,
|
||||||
|
type: ConfigOptionType.Number,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_BARCODE_MAX_PAGES',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_enable_tag',
|
||||||
|
title: $localize`Enable Tag Detection`,
|
||||||
|
type: ConfigOptionType.Boolean,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_ENABLE_TAG_BARCODE',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'barcode_tag_mapping',
|
||||||
|
title: $localize`Tag Mapping`,
|
||||||
|
type: ConfigOptionType.JSON,
|
||||||
|
config_key: 'PAPERLESS_CONSUMER_TAG_BARCODE_MAPPING',
|
||||||
|
category: ConfigCategory.Barcode,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export interface PaperlessConfig extends ObjectWithId {
|
export interface PaperlessConfig extends ObjectWithId {
|
||||||
@ -198,4 +276,15 @@ export interface PaperlessConfig extends ObjectWithId {
|
|||||||
user_args: object
|
user_args: object
|
||||||
app_logo: string
|
app_logo: string
|
||||||
app_title: string
|
app_title: string
|
||||||
|
barcodes_enabled: boolean
|
||||||
|
barcode_enable_tiff_support: boolean
|
||||||
|
barcode_string: string
|
||||||
|
barcode_retain_split_pages: boolean
|
||||||
|
barcode_enable_asn: boolean
|
||||||
|
barcode_asn_prefix: string
|
||||||
|
barcode_upscale: number
|
||||||
|
barcode_dpi: number
|
||||||
|
barcode_max_pages: number
|
||||||
|
barcode_enable_tag: boolean
|
||||||
|
barcode_tag_mapping: object
|
||||||
}
|
}
|
||||||
|
@ -15,33 +15,6 @@ import {
|
|||||||
WebsocketStatusService,
|
WebsocketStatusService,
|
||||||
} from './websocket-status.service'
|
} from './websocket-status.service'
|
||||||
|
|
||||||
const files = [
|
|
||||||
{
|
|
||||||
lastModified: 1693349892540,
|
|
||||||
lastModifiedDate: new Date(),
|
|
||||||
name: 'file1.pdf',
|
|
||||||
size: 386,
|
|
||||||
type: 'application/pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
lastModified: 1695618533892,
|
|
||||||
lastModifiedDate: new Date(),
|
|
||||||
name: 'file2.pdf',
|
|
||||||
size: 358265,
|
|
||||||
type: 'application/pdf',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const fileList = {
|
|
||||||
item: (x) => {
|
|
||||||
return new File(
|
|
||||||
[new Blob(['testing'], { type: files[x].type })],
|
|
||||||
files[x].name
|
|
||||||
)
|
|
||||||
},
|
|
||||||
length: files.length,
|
|
||||||
} as unknown as FileList
|
|
||||||
|
|
||||||
describe('UploadDocumentsService', () => {
|
describe('UploadDocumentsService', () => {
|
||||||
let httpTestingController: HttpTestingController
|
let httpTestingController: HttpTestingController
|
||||||
let uploadDocumentsService: UploadDocumentsService
|
let uploadDocumentsService: UploadDocumentsService
|
||||||
@ -68,7 +41,11 @@ describe('UploadDocumentsService', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('calls post_document api endpoint on upload', () => {
|
it('calls post_document api endpoint on upload', () => {
|
||||||
uploadDocumentsService.uploadFiles(fileList)
|
const file = new File(
|
||||||
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
|
'file.pdf'
|
||||||
|
)
|
||||||
|
uploadDocumentsService.uploadFile(file)
|
||||||
const req = httpTestingController.match(
|
const req = httpTestingController.match(
|
||||||
`${environment.apiBaseUrl}documents/post_document/`
|
`${environment.apiBaseUrl}documents/post_document/`
|
||||||
)
|
)
|
||||||
@ -78,7 +55,16 @@ describe('UploadDocumentsService', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('updates progress during upload and failure', () => {
|
it('updates progress during upload and failure', () => {
|
||||||
uploadDocumentsService.uploadFiles(fileList)
|
const file = new File(
|
||||||
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
|
'file.pdf'
|
||||||
|
)
|
||||||
|
const file2 = new File(
|
||||||
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
|
'file2.pdf'
|
||||||
|
)
|
||||||
|
uploadDocumentsService.uploadFile(file)
|
||||||
|
uploadDocumentsService.uploadFile(file2)
|
||||||
|
|
||||||
expect(websocketStatusService.getConsumerStatusNotCompleted()).toHaveLength(
|
expect(websocketStatusService.getConsumerStatusNotCompleted()).toHaveLength(
|
||||||
2
|
2
|
||||||
@ -103,7 +89,11 @@ describe('UploadDocumentsService', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('updates progress on failure', () => {
|
it('updates progress on failure', () => {
|
||||||
uploadDocumentsService.uploadFiles(fileList)
|
const file = new File(
|
||||||
|
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||||
|
'file.pdf'
|
||||||
|
)
|
||||||
|
uploadDocumentsService.uploadFile(file)
|
||||||
|
|
||||||
let req = httpTestingController.match(
|
let req = httpTestingController.match(
|
||||||
`${environment.apiBaseUrl}documents/post_document/`
|
`${environment.apiBaseUrl}documents/post_document/`
|
||||||
@ -125,7 +115,7 @@ describe('UploadDocumentsService', () => {
|
|||||||
websocketStatusService.getConsumerStatus(FileStatusPhase.FAILED)
|
websocketStatusService.getConsumerStatus(FileStatusPhase.FAILED)
|
||||||
).toHaveLength(1)
|
).toHaveLength(1)
|
||||||
|
|
||||||
uploadDocumentsService.uploadFiles(fileList)
|
uploadDocumentsService.uploadFile(file)
|
||||||
|
|
||||||
req = httpTestingController.match(
|
req = httpTestingController.match(
|
||||||
`${environment.apiBaseUrl}documents/post_document/`
|
`${environment.apiBaseUrl}documents/post_document/`
|
||||||
@ -143,35 +133,4 @@ describe('UploadDocumentsService', () => {
|
|||||||
websocketStatusService.getConsumerStatus(FileStatusPhase.FAILED)
|
websocketStatusService.getConsumerStatus(FileStatusPhase.FAILED)
|
||||||
).toHaveLength(2)
|
).toHaveLength(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('accepts files via drag and drop', () => {
|
|
||||||
const uploadSpy = jest.spyOn(
|
|
||||||
UploadDocumentsService.prototype as any,
|
|
||||||
'uploadFile'
|
|
||||||
)
|
|
||||||
const fileEntry = {
|
|
||||||
name: 'file.pdf',
|
|
||||||
isDirectory: false,
|
|
||||||
isFile: true,
|
|
||||||
file: (callback) => {
|
|
||||||
return callback(
|
|
||||||
new File(
|
|
||||||
[new Blob(['testing'], { type: 'application/pdf' })],
|
|
||||||
'file.pdf'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
uploadDocumentsService.onNgxFileDrop([
|
|
||||||
{
|
|
||||||
relativePath: 'path/to/file.pdf',
|
|
||||||
fileEntry,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
expect(uploadSpy).toHaveBeenCalled()
|
|
||||||
|
|
||||||
let req = httpTestingController.match(
|
|
||||||
`${environment.apiBaseUrl}documents/post_document/`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { HttpEventType } from '@angular/common/http'
|
import { HttpEventType } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop'
|
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { DocumentService } from './rest/document.service'
|
import { DocumentService } from './rest/document.service'
|
||||||
import {
|
import {
|
||||||
@ -19,22 +18,7 @@ export class UploadDocumentsService {
|
|||||||
private websocketStatusService: WebsocketStatusService
|
private websocketStatusService: WebsocketStatusService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
onNgxFileDrop(files: NgxFileDropEntry[]) {
|
public uploadFile(file: File) {
|
||||||
for (const droppedFile of files) {
|
|
||||||
if (droppedFile.fileEntry.isFile) {
|
|
||||||
const fileEntry = droppedFile.fileEntry as FileSystemFileEntry
|
|
||||||
fileEntry.file((file: File) => this.uploadFile(file))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadFiles(files: FileList) {
|
|
||||||
for (let index = 0; index < files.length; index++) {
|
|
||||||
this.uploadFile(files.item(index))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private uploadFile(file: File) {
|
|
||||||
let formData = new FormData()
|
let formData = new FormData()
|
||||||
formData.append('document', file, file.name)
|
formData.append('document', file, file.name)
|
||||||
formData.append('from_webui', 'true')
|
formData.append('from_webui', 'true')
|
||||||
|
@ -135,7 +135,6 @@ import {
|
|||||||
} from 'ngx-bootstrap-icons'
|
} from 'ngx-bootstrap-icons'
|
||||||
import { ColorSliderModule } from 'ngx-color/slider'
|
import { ColorSliderModule } from 'ngx-color/slider'
|
||||||
import { CookieService } from 'ngx-cookie-service'
|
import { CookieService } from 'ngx-cookie-service'
|
||||||
import { NgxFileDropModule } from 'ngx-file-drop'
|
|
||||||
import { TourNgBootstrapModule } from 'ngx-ui-tour-ng-bootstrap'
|
import { TourNgBootstrapModule } from 'ngx-ui-tour-ng-bootstrap'
|
||||||
import { AppRoutingModule } from './app/app-routing.module'
|
import { AppRoutingModule } from './app/app-routing.module'
|
||||||
import { AppComponent } from './app/app.component'
|
import { AppComponent } from './app/app.component'
|
||||||
@ -353,7 +352,6 @@ bootstrapApplication(AppComponent, {
|
|||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
PdfViewerModule,
|
PdfViewerModule,
|
||||||
NgxFileDropModule,
|
|
||||||
NgSelectModule,
|
NgSelectModule,
|
||||||
ColorSliderModule,
|
ColorSliderModule,
|
||||||
TourNgBootstrapModule,
|
TourNgBootstrapModule,
|
||||||
|
@ -15,13 +15,16 @@ from pikepdf import Pdf
|
|||||||
|
|
||||||
from documents.converters import convert_from_tiff_to_pdf
|
from documents.converters import convert_from_tiff_to_pdf
|
||||||
from documents.data_models import ConsumableDocument
|
from documents.data_models import ConsumableDocument
|
||||||
|
from documents.data_models import DocumentMetadataOverrides
|
||||||
from documents.models import Tag
|
from documents.models import Tag
|
||||||
from documents.plugins.base import ConsumeTaskPlugin
|
from documents.plugins.base import ConsumeTaskPlugin
|
||||||
from documents.plugins.base import StopConsumeTaskError
|
from documents.plugins.base import StopConsumeTaskError
|
||||||
|
from documents.plugins.helpers import ProgressManager
|
||||||
from documents.plugins.helpers import ProgressStatusOptions
|
from documents.plugins.helpers import ProgressStatusOptions
|
||||||
from documents.utils import copy_basic_file_stats
|
from documents.utils import copy_basic_file_stats
|
||||||
from documents.utils import copy_file_with_basic_stats
|
from documents.utils import copy_file_with_basic_stats
|
||||||
from documents.utils import maybe_override_pixel_limit
|
from documents.utils import maybe_override_pixel_limit
|
||||||
|
from paperless.config import BarcodeConfig
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
@ -39,6 +42,7 @@ class Barcode:
|
|||||||
|
|
||||||
page: int
|
page: int
|
||||||
value: str
|
value: str
|
||||||
|
settings: BarcodeConfig
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_separator(self) -> bool:
|
def is_separator(self) -> bool:
|
||||||
@ -46,7 +50,7 @@ class Barcode:
|
|||||||
Returns True if the barcode value equals the configured separation value,
|
Returns True if the barcode value equals the configured separation value,
|
||||||
False otherwise
|
False otherwise
|
||||||
"""
|
"""
|
||||||
return self.value == settings.CONSUMER_BARCODE_STRING
|
return self.value == self.settings.barcode_string
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_asn(self) -> bool:
|
def is_asn(self) -> bool:
|
||||||
@ -54,7 +58,7 @@ class Barcode:
|
|||||||
Returns True if the barcode value matches the configured ASN prefix,
|
Returns True if the barcode value matches the configured ASN prefix,
|
||||||
False otherwise
|
False otherwise
|
||||||
"""
|
"""
|
||||||
return self.value.startswith(settings.CONSUMER_ASN_BARCODE_PREFIX)
|
return self.value.startswith(self.settings.barcode_asn_prefix)
|
||||||
|
|
||||||
|
|
||||||
class BarcodePlugin(ConsumeTaskPlugin):
|
class BarcodePlugin(ConsumeTaskPlugin):
|
||||||
@ -67,17 +71,41 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
- ASN from barcode detection is enabled or
|
- ASN from barcode detection is enabled or
|
||||||
- Barcode support is enabled and the mime type is supported
|
- Barcode support is enabled and the mime type is supported
|
||||||
"""
|
"""
|
||||||
if settings.CONSUMER_BARCODE_TIFF_SUPPORT:
|
if self.settings.barcode_enable_tiff_support:
|
||||||
supported_mimes: set[str] = {"application/pdf", "image/tiff"}
|
supported_mimes: set[str] = {"application/pdf", "image/tiff"}
|
||||||
else:
|
else:
|
||||||
supported_mimes = {"application/pdf"}
|
supported_mimes = {"application/pdf"}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
settings.CONSUMER_ENABLE_ASN_BARCODE
|
self.settings.barcode_enable_asn
|
||||||
or settings.CONSUMER_ENABLE_BARCODES
|
or self.settings.barcodes_enabled
|
||||||
or settings.CONSUMER_ENABLE_TAG_BARCODE
|
or self.settings.barcode_enable_tag
|
||||||
) and self.input_doc.mime_type in supported_mimes
|
) and self.input_doc.mime_type in supported_mimes
|
||||||
|
|
||||||
|
def get_settings(self) -> BarcodeConfig:
|
||||||
|
"""
|
||||||
|
Returns the settings for this plugin (Django settings or app config)
|
||||||
|
"""
|
||||||
|
return BarcodeConfig()
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
input_doc: ConsumableDocument,
|
||||||
|
metadata: DocumentMetadataOverrides,
|
||||||
|
status_mgr: ProgressManager,
|
||||||
|
base_tmp_dir: Path,
|
||||||
|
task_id: str,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(
|
||||||
|
input_doc,
|
||||||
|
metadata,
|
||||||
|
status_mgr,
|
||||||
|
base_tmp_dir,
|
||||||
|
task_id,
|
||||||
|
)
|
||||||
|
# need these for able_to_run
|
||||||
|
self.settings = self.get_settings()
|
||||||
|
|
||||||
def setup(self) -> None:
|
def setup(self) -> None:
|
||||||
self.temp_dir = tempfile.TemporaryDirectory(
|
self.temp_dir = tempfile.TemporaryDirectory(
|
||||||
dir=self.base_tmp_dir,
|
dir=self.base_tmp_dir,
|
||||||
@ -99,7 +127,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
|
|
||||||
# try reading tags from barcodes
|
# try reading tags from barcodes
|
||||||
if (
|
if (
|
||||||
settings.CONSUMER_ENABLE_TAG_BARCODE
|
self.settings.barcode_enable_tag
|
||||||
and (tags := self.tags) is not None
|
and (tags := self.tags) is not None
|
||||||
and len(tags) > 0
|
and len(tags) > 0
|
||||||
):
|
):
|
||||||
@ -110,7 +138,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
logger.info(f"Found tags in barcode: {tags}")
|
logger.info(f"Found tags in barcode: {tags}")
|
||||||
|
|
||||||
# Lastly attempt to split documents
|
# Lastly attempt to split documents
|
||||||
if settings.CONSUMER_ENABLE_BARCODES and (
|
if self.settings.barcodes_enabled and (
|
||||||
separator_pages := self.get_separation_pages()
|
separator_pages := self.get_separation_pages()
|
||||||
):
|
):
|
||||||
# We have pages to split against
|
# We have pages to split against
|
||||||
@ -155,10 +183,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
|
|
||||||
# Update/overwrite an ASN if possible
|
# Update/overwrite an ASN if possible
|
||||||
# After splitting, as otherwise each split document gets the same ASN
|
# After splitting, as otherwise each split document gets the same ASN
|
||||||
if (
|
if self.settings.barcode_enable_asn and (located_asn := self.asn) is not None:
|
||||||
settings.CONSUMER_ENABLE_ASN_BARCODE
|
|
||||||
and (located_asn := self.asn) is not None
|
|
||||||
):
|
|
||||||
logger.info(f"Found ASN in barcode: {located_asn}")
|
logger.info(f"Found ASN in barcode: {located_asn}")
|
||||||
self.metadata.asn = located_asn
|
self.metadata.asn = located_asn
|
||||||
|
|
||||||
@ -245,8 +270,8 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
# Get limit from configuration
|
# Get limit from configuration
|
||||||
barcode_max_pages: int = (
|
barcode_max_pages: int = (
|
||||||
num_of_pages
|
num_of_pages
|
||||||
if settings.CONSUMER_BARCODE_MAX_PAGES == 0
|
if self.settings.barcode_max_pages == 0
|
||||||
else settings.CONSUMER_BARCODE_MAX_PAGES
|
else self.settings.barcode_max_pages
|
||||||
)
|
)
|
||||||
|
|
||||||
if barcode_max_pages < num_of_pages: # pragma: no cover
|
if barcode_max_pages < num_of_pages: # pragma: no cover
|
||||||
@ -261,7 +286,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
# Convert page to image
|
# Convert page to image
|
||||||
page = convert_from_path(
|
page = convert_from_path(
|
||||||
self.pdf_file,
|
self.pdf_file,
|
||||||
dpi=settings.CONSUMER_BARCODE_DPI,
|
dpi=self.settings.barcode_dpi,
|
||||||
output_folder=self.temp_dir.name,
|
output_folder=self.temp_dir.name,
|
||||||
first_page=current_page_number + 1,
|
first_page=current_page_number + 1,
|
||||||
last_page=current_page_number + 1,
|
last_page=current_page_number + 1,
|
||||||
@ -272,7 +297,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
logger.debug(f"Image is at {page_filepath}")
|
logger.debug(f"Image is at {page_filepath}")
|
||||||
|
|
||||||
# Upscale image if configured
|
# Upscale image if configured
|
||||||
factor = settings.CONSUMER_BARCODE_UPSCALE
|
factor = self.settings.barcode_upscale
|
||||||
if factor > 1.0:
|
if factor > 1.0:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Upscaling image by {factor} for better barcode detection",
|
f"Upscaling image by {factor} for better barcode detection",
|
||||||
@ -285,7 +310,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
# Detect barcodes
|
# Detect barcodes
|
||||||
for barcode_value in reader(page):
|
for barcode_value in reader(page):
|
||||||
self.barcodes.append(
|
self.barcodes.append(
|
||||||
Barcode(current_page_number, barcode_value),
|
Barcode(current_page_number, barcode_value, self.settings),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Delete temporary image file
|
# Delete temporary image file
|
||||||
@ -308,7 +333,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
def asn(self) -> int | None:
|
def asn(self) -> int | None:
|
||||||
"""
|
"""
|
||||||
Search the parsed barcodes for any ASNs.
|
Search the parsed barcodes for any ASNs.
|
||||||
The first barcode that starts with CONSUMER_ASN_BARCODE_PREFIX
|
The first barcode that starts with barcode_asn_prefix
|
||||||
is considered the ASN to be used.
|
is considered the ASN to be used.
|
||||||
Returns the detected ASN (or None)
|
Returns the detected ASN (or None)
|
||||||
"""
|
"""
|
||||||
@ -317,7 +342,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
# Ensure the barcodes have been read
|
# Ensure the barcodes have been read
|
||||||
self.detect()
|
self.detect()
|
||||||
|
|
||||||
# get the first barcode that starts with CONSUMER_ASN_BARCODE_PREFIX
|
# get the first barcode that starts with barcode_asn_prefix
|
||||||
asn_text: str | None = next(
|
asn_text: str | None = next(
|
||||||
(x.value for x in self.barcodes if x.is_asn),
|
(x.value for x in self.barcodes if x.is_asn),
|
||||||
None,
|
None,
|
||||||
@ -326,7 +351,7 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
if asn_text:
|
if asn_text:
|
||||||
logger.debug(f"Found ASN Barcode: {asn_text}")
|
logger.debug(f"Found ASN Barcode: {asn_text}")
|
||||||
# remove the prefix and remove whitespace
|
# remove the prefix and remove whitespace
|
||||||
asn_text = asn_text[len(settings.CONSUMER_ASN_BARCODE_PREFIX) :].strip()
|
asn_text = asn_text[len(self.settings.barcode_asn_prefix) :].strip()
|
||||||
|
|
||||||
# remove non-numeric parts of the remaining string
|
# remove non-numeric parts of the remaining string
|
||||||
asn_text = re.sub(r"\D", "", asn_text)
|
asn_text = re.sub(r"\D", "", asn_text)
|
||||||
@ -356,9 +381,9 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
for raw in tag_texts.split(","):
|
for raw in tag_texts.split(","):
|
||||||
try:
|
try:
|
||||||
tag_str: str | None = None
|
tag_str: str | None = None
|
||||||
for regex in settings.CONSUMER_TAG_BARCODE_MAPPING:
|
for regex in self.settings.barcode_tag_mapping:
|
||||||
if re.match(regex, raw, flags=re.IGNORECASE):
|
if re.match(regex, raw, flags=re.IGNORECASE):
|
||||||
sub = settings.CONSUMER_TAG_BARCODE_MAPPING[regex]
|
sub = self.settings.barcode_tag_mapping[regex]
|
||||||
tag_str = (
|
tag_str = (
|
||||||
re.sub(regex, sub, raw, flags=re.IGNORECASE)
|
re.sub(regex, sub, raw, flags=re.IGNORECASE)
|
||||||
if sub
|
if sub
|
||||||
@ -394,13 +419,13 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
"""
|
"""
|
||||||
# filter all barcodes for the separator string
|
# filter all barcodes for the separator string
|
||||||
# get the page numbers of the separating barcodes
|
# get the page numbers of the separating barcodes
|
||||||
retain = settings.CONSUMER_BARCODE_RETAIN_SPLIT_PAGES
|
retain = self.settings.barcode_retain_split_pages
|
||||||
separator_pages = {
|
separator_pages = {
|
||||||
bc.page: retain
|
bc.page: retain
|
||||||
for bc in self.barcodes
|
for bc in self.barcodes
|
||||||
if bc.is_separator and (not retain or (retain and bc.page > 0))
|
if bc.is_separator and (not retain or (retain and bc.page > 0))
|
||||||
} # as below, dont include the first page if retain is enabled
|
} # as below, dont include the first page if retain is enabled
|
||||||
if not settings.CONSUMER_ENABLE_ASN_BARCODE:
|
if not self.settings.barcode_enable_asn:
|
||||||
return separator_pages
|
return separator_pages
|
||||||
|
|
||||||
# add the page numbers of the ASN barcodes
|
# add the page numbers of the ASN barcodes
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-15 19:18
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("documents", "1065_workflowaction_assign_custom_fields_values"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="workflowtrigger",
|
||||||
|
name="schedule_offset_days",
|
||||||
|
field=models.IntegerField(
|
||||||
|
default=0,
|
||||||
|
help_text="The number of days to offset the schedule trigger by.",
|
||||||
|
verbose_name="schedule offset days",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -1019,7 +1019,7 @@ class WorkflowTrigger(models.Model):
|
|||||||
verbose_name=_("has this correspondent"),
|
verbose_name=_("has this correspondent"),
|
||||||
)
|
)
|
||||||
|
|
||||||
schedule_offset_days = models.PositiveIntegerField(
|
schedule_offset_days = models.IntegerField(
|
||||||
_("schedule offset days"),
|
_("schedule offset days"),
|
||||||
default=0,
|
default=0,
|
||||||
help_text=_(
|
help_text=_(
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import timedelta
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
@ -357,7 +357,7 @@ def empty_trash(doc_ids=None):
|
|||||||
if doc_ids is not None
|
if doc_ids is not None
|
||||||
else Document.deleted_objects.filter(
|
else Document.deleted_objects.filter(
|
||||||
deleted_at__lt=timezone.localtime(timezone.now())
|
deleted_at__lt=timezone.localtime(timezone.now())
|
||||||
- timedelta(
|
- datetime.timedelta(
|
||||||
days=settings.EMPTY_TRASH_DELAY,
|
days=settings.EMPTY_TRASH_DELAY,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -397,6 +397,7 @@ def check_scheduled_workflows():
|
|||||||
)
|
)
|
||||||
if scheduled_workflows.count() > 0:
|
if scheduled_workflows.count() > 0:
|
||||||
logger.debug(f"Checking {len(scheduled_workflows)} scheduled workflows")
|
logger.debug(f"Checking {len(scheduled_workflows)} scheduled workflows")
|
||||||
|
now = timezone.now()
|
||||||
for workflow in scheduled_workflows:
|
for workflow in scheduled_workflows:
|
||||||
schedule_triggers = workflow.triggers.filter(
|
schedule_triggers = workflow.triggers.filter(
|
||||||
type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
|
type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
|
||||||
@ -404,31 +405,60 @@ def check_scheduled_workflows():
|
|||||||
trigger: WorkflowTrigger
|
trigger: WorkflowTrigger
|
||||||
for trigger in schedule_triggers:
|
for trigger in schedule_triggers:
|
||||||
documents = Document.objects.none()
|
documents = Document.objects.none()
|
||||||
offset_td = timedelta(days=trigger.schedule_offset_days)
|
offset_td = datetime.timedelta(days=-trigger.schedule_offset_days)
|
||||||
|
threshold = now - offset_td
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Checking trigger {trigger} with offset {offset_td} against field: {trigger.schedule_date_field}",
|
f"Trigger {trigger.id}: checking if (date + {offset_td}) <= now ({now})",
|
||||||
)
|
)
|
||||||
|
|
||||||
match trigger.schedule_date_field:
|
match trigger.schedule_date_field:
|
||||||
case WorkflowTrigger.ScheduleDateField.ADDED:
|
case WorkflowTrigger.ScheduleDateField.ADDED:
|
||||||
documents = Document.objects.filter(
|
documents = Document.objects.filter(added__lte=threshold)
|
||||||
added__lt=timezone.now() - offset_td,
|
|
||||||
)
|
|
||||||
case WorkflowTrigger.ScheduleDateField.CREATED:
|
case WorkflowTrigger.ScheduleDateField.CREATED:
|
||||||
documents = Document.objects.filter(
|
documents = Document.objects.filter(created__lte=threshold)
|
||||||
created__lt=timezone.now() - offset_td,
|
|
||||||
)
|
|
||||||
case WorkflowTrigger.ScheduleDateField.MODIFIED:
|
case WorkflowTrigger.ScheduleDateField.MODIFIED:
|
||||||
documents = Document.objects.filter(
|
documents = Document.objects.filter(modified__lte=threshold)
|
||||||
modified__lt=timezone.now() - offset_td,
|
|
||||||
)
|
|
||||||
case WorkflowTrigger.ScheduleDateField.CUSTOM_FIELD:
|
case WorkflowTrigger.ScheduleDateField.CUSTOM_FIELD:
|
||||||
cf_instances = CustomFieldInstance.objects.filter(
|
# cap earliest date to avoid massive scans
|
||||||
field=trigger.schedule_date_custom_field,
|
earliest_date = now - datetime.timedelta(days=365)
|
||||||
value_date__lt=timezone.now() - offset_td,
|
if offset_td.days < -365:
|
||||||
)
|
logger.warning(
|
||||||
documents = Document.objects.filter(
|
f"Trigger {trigger.id} has large negative offset ({offset_td.days}), "
|
||||||
id__in=cf_instances.values_list("document", flat=True),
|
f"limiting earliest scan date to {earliest_date}",
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_filter_kwargs = {
|
||||||
|
"field": trigger.schedule_date_custom_field,
|
||||||
|
"value_date__isnull": False,
|
||||||
|
"value_date__lte": threshold,
|
||||||
|
"value_date__gte": earliest_date,
|
||||||
|
}
|
||||||
|
|
||||||
|
recent_cf_instances = CustomFieldInstance.objects.filter(
|
||||||
|
**cf_filter_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
matched_ids = [
|
||||||
|
cfi.document_id
|
||||||
|
for cfi in recent_cf_instances
|
||||||
|
if cfi.value_date
|
||||||
|
and (
|
||||||
|
timezone.make_aware(
|
||||||
|
datetime.datetime.combine(
|
||||||
|
cfi.value_date,
|
||||||
|
datetime.time.min,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
+ offset_td
|
||||||
|
<= now
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
documents = Document.objects.filter(id__in=matched_ids)
|
||||||
|
|
||||||
if documents.count() > 0:
|
if documents.count() > 0:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Found {documents.count()} documents for trigger {trigger}",
|
f"Found {documents.count()} documents for trigger {trigger}",
|
||||||
@ -440,18 +470,18 @@ def check_scheduled_workflows():
|
|||||||
workflow=workflow,
|
workflow=workflow,
|
||||||
).order_by("-run_at")
|
).order_by("-run_at")
|
||||||
if not trigger.schedule_is_recurring and workflow_runs.exists():
|
if not trigger.schedule_is_recurring and workflow_runs.exists():
|
||||||
# schedule is non-recurring and the workflow has already been run
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Skipping document {document} for non-recurring workflow {workflow} as it has already been run",
|
f"Skipping document {document} for non-recurring workflow {workflow} as it has already been run",
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
elif (
|
|
||||||
|
if (
|
||||||
trigger.schedule_is_recurring
|
trigger.schedule_is_recurring
|
||||||
and workflow_runs.exists()
|
and workflow_runs.exists()
|
||||||
and (
|
and (
|
||||||
workflow_runs.last().run_at
|
workflow_runs.last().run_at
|
||||||
> timezone.now()
|
> now
|
||||||
- timedelta(
|
- datetime.timedelta(
|
||||||
days=trigger.schedule_recurring_interval_days,
|
days=trigger.schedule_recurring_interval_days,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -32,28 +32,39 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
self.assertEqual(
|
self.maxDiff = None
|
||||||
json.dumps(response.data[0]),
|
|
||||||
json.dumps(
|
self.assertDictEqual(
|
||||||
{
|
response.data[0],
|
||||||
"id": 1,
|
{
|
||||||
"user_args": None,
|
"id": 1,
|
||||||
"output_type": None,
|
"output_type": None,
|
||||||
"pages": None,
|
"pages": None,
|
||||||
"language": None,
|
"language": None,
|
||||||
"mode": None,
|
"mode": None,
|
||||||
"skip_archive_file": None,
|
"skip_archive_file": None,
|
||||||
"image_dpi": None,
|
"image_dpi": None,
|
||||||
"unpaper_clean": None,
|
"unpaper_clean": None,
|
||||||
"deskew": None,
|
"deskew": None,
|
||||||
"rotate_pages": None,
|
"rotate_pages": None,
|
||||||
"rotate_pages_threshold": None,
|
"rotate_pages_threshold": None,
|
||||||
"max_image_pixels": None,
|
"max_image_pixels": None,
|
||||||
"color_conversion_strategy": None,
|
"color_conversion_strategy": None,
|
||||||
"app_title": None,
|
"user_args": None,
|
||||||
"app_logo": None,
|
"app_title": None,
|
||||||
},
|
"app_logo": None,
|
||||||
),
|
"barcodes_enabled": None,
|
||||||
|
"barcode_enable_tiff_support": None,
|
||||||
|
"barcode_string": None,
|
||||||
|
"barcode_retain_split_pages": None,
|
||||||
|
"barcode_enable_asn": None,
|
||||||
|
"barcode_asn_prefix": None,
|
||||||
|
"barcode_upscale": None,
|
||||||
|
"barcode_dpi": None,
|
||||||
|
"barcode_max_pages": None,
|
||||||
|
"barcode_enable_tag": None,
|
||||||
|
"barcode_tag_mapping": None,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_api_get_ui_settings_with_config(self):
|
def test_api_get_ui_settings_with_config(self):
|
||||||
@ -118,6 +129,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
{
|
{
|
||||||
"user_args": "",
|
"user_args": "",
|
||||||
"language": "",
|
"language": "",
|
||||||
|
"barcode_tag_mapping": "",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
@ -126,6 +138,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
config = ApplicationConfiguration.objects.first()
|
config = ApplicationConfiguration.objects.first()
|
||||||
self.assertEqual(config.user_args, None)
|
self.assertEqual(config.user_args, None)
|
||||||
self.assertEqual(config.language, None)
|
self.assertEqual(config.language, None)
|
||||||
|
self.assertEqual(config.barcode_tag_mapping, None)
|
||||||
|
|
||||||
def test_api_replace_app_logo(self):
|
def test_api_replace_app_logo(self):
|
||||||
"""
|
"""
|
||||||
|
@ -136,6 +136,36 @@ class TestApiProfile(DirectoriesMixin, APITestCase):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_profile_w_social_removed_app(self):
|
||||||
|
"""
|
||||||
|
GIVEN:
|
||||||
|
- Configured user and setup social account
|
||||||
|
- Social app has been removed
|
||||||
|
WHEN:
|
||||||
|
- API call is made to get profile
|
||||||
|
THEN:
|
||||||
|
- Profile is returned with "Unknown App" as name
|
||||||
|
"""
|
||||||
|
self.setupSocialAccount()
|
||||||
|
|
||||||
|
# Remove the social app
|
||||||
|
SocialApp.objects.get(provider_id="keycloak-test").delete()
|
||||||
|
|
||||||
|
response = self.client.get(self.ENDPOINT)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
response.data["social_accounts"],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"provider": "keycloak-test",
|
||||||
|
"name": "Unknown App",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_update_profile(self):
|
def test_update_profile(self):
|
||||||
"""
|
"""
|
||||||
GIVEN:
|
GIVEN:
|
||||||
|
@ -22,6 +22,7 @@ from documents.tests.utils import DocumentConsumeDelayMixin
|
|||||||
from documents.tests.utils import DummyProgressManager
|
from documents.tests.utils import DummyProgressManager
|
||||||
from documents.tests.utils import FileSystemAssertsMixin
|
from documents.tests.utils import FileSystemAssertsMixin
|
||||||
from documents.tests.utils import SampleDirMixin
|
from documents.tests.utils import SampleDirMixin
|
||||||
|
from paperless.models import ApplicationConfiguration
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import zxingcpp # noqa: F401
|
import zxingcpp # noqa: F401
|
||||||
@ -547,6 +548,27 @@ class TestBarcode(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_barcode_config(self):
|
||||||
|
"""
|
||||||
|
GIVEN:
|
||||||
|
- Barcode app config is set (settings are not)
|
||||||
|
WHEN:
|
||||||
|
- Document with barcode is processed
|
||||||
|
THEN:
|
||||||
|
- The barcode config is used
|
||||||
|
"""
|
||||||
|
app_config = ApplicationConfiguration.objects.first()
|
||||||
|
app_config.barcodes_enabled = True
|
||||||
|
app_config.barcode_string = "CUSTOM BARCODE"
|
||||||
|
app_config.save()
|
||||||
|
test_file = self.BARCODE_SAMPLE_DIR / "barcode-39-custom.pdf"
|
||||||
|
with self.get_reader(test_file) as reader:
|
||||||
|
reader.detect()
|
||||||
|
separator_page_numbers = reader.get_separation_pages()
|
||||||
|
|
||||||
|
self.assertEqual(reader.pdf_file, test_file)
|
||||||
|
self.assertDictEqual(separator_page_numbers, {0: False})
|
||||||
|
|
||||||
|
|
||||||
@override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR")
|
@override_settings(CONSUMER_BARCODE_SCANNER="PYZBAR")
|
||||||
class TestBarcodeNewConsume(
|
class TestBarcodeNewConsume(
|
||||||
|
@ -1336,6 +1336,8 @@ class TestWorkflows(
|
|||||||
GIVEN:
|
GIVEN:
|
||||||
- Existing workflow with SCHEDULED trigger against the created field and action that assigns owner
|
- Existing workflow with SCHEDULED trigger against the created field and action that assigns owner
|
||||||
- Existing doc that matches the trigger
|
- Existing doc that matches the trigger
|
||||||
|
- Workflow set to trigger at (now - offset) = now - 1 day
|
||||||
|
- Document created date is 2 days ago → trigger condition met
|
||||||
WHEN:
|
WHEN:
|
||||||
- Scheduled workflows are checked
|
- Scheduled workflows are checked
|
||||||
THEN:
|
THEN:
|
||||||
@ -1359,7 +1361,7 @@ class TestWorkflows(
|
|||||||
w.save()
|
w.save()
|
||||||
|
|
||||||
now = timezone.localtime(timezone.now())
|
now = timezone.localtime(timezone.now())
|
||||||
created = now - timedelta(weeks=520)
|
created = now - timedelta(days=2)
|
||||||
doc = Document.objects.create(
|
doc = Document.objects.create(
|
||||||
title="sample test",
|
title="sample test",
|
||||||
correspondent=self.c,
|
correspondent=self.c,
|
||||||
@ -1377,6 +1379,8 @@ class TestWorkflows(
|
|||||||
GIVEN:
|
GIVEN:
|
||||||
- Existing workflow with SCHEDULED trigger against the added field and action that assigns owner
|
- Existing workflow with SCHEDULED trigger against the added field and action that assigns owner
|
||||||
- Existing doc that matches the trigger
|
- Existing doc that matches the trigger
|
||||||
|
- Workflow set to trigger at (now - offset) = now - 1 day
|
||||||
|
- Document added date is 365 days ago
|
||||||
WHEN:
|
WHEN:
|
||||||
- Scheduled workflows are checked
|
- Scheduled workflows are checked
|
||||||
THEN:
|
THEN:
|
||||||
@ -1418,6 +1422,8 @@ class TestWorkflows(
|
|||||||
GIVEN:
|
GIVEN:
|
||||||
- Existing workflow with SCHEDULED trigger against the modified field and action that assigns owner
|
- Existing workflow with SCHEDULED trigger against the modified field and action that assigns owner
|
||||||
- Existing doc that matches the trigger
|
- Existing doc that matches the trigger
|
||||||
|
- Workflow set to trigger at (now - offset) = now - 1 day
|
||||||
|
- Document modified date is mocked as sufficiently in the past
|
||||||
WHEN:
|
WHEN:
|
||||||
- Scheduled workflows are checked
|
- Scheduled workflows are checked
|
||||||
THEN:
|
THEN:
|
||||||
@ -1458,6 +1464,8 @@ class TestWorkflows(
|
|||||||
GIVEN:
|
GIVEN:
|
||||||
- Existing workflow with SCHEDULED trigger against a custom field and action that assigns owner
|
- Existing workflow with SCHEDULED trigger against a custom field and action that assigns owner
|
||||||
- Existing doc that matches the trigger
|
- Existing doc that matches the trigger
|
||||||
|
- Workflow set to trigger at (now - offset) = now - 1 day
|
||||||
|
- Custom field date is 2 days ago
|
||||||
WHEN:
|
WHEN:
|
||||||
- Scheduled workflows are checked
|
- Scheduled workflows are checked
|
||||||
THEN:
|
THEN:
|
||||||
@ -1502,6 +1510,7 @@ class TestWorkflows(
|
|||||||
GIVEN:
|
GIVEN:
|
||||||
- Existing workflow with SCHEDULED trigger
|
- Existing workflow with SCHEDULED trigger
|
||||||
- Existing doc that has already had the workflow run
|
- Existing doc that has already had the workflow run
|
||||||
|
- Document created 2 days ago, workflow offset = 1 day → trigger time = yesterday
|
||||||
WHEN:
|
WHEN:
|
||||||
- Scheduled workflows are checked
|
- Scheduled workflows are checked
|
||||||
THEN:
|
THEN:
|
||||||
@ -1552,6 +1561,7 @@ class TestWorkflows(
|
|||||||
GIVEN:
|
GIVEN:
|
||||||
- Existing workflow with SCHEDULED trigger and recurring interval of 7 days
|
- Existing workflow with SCHEDULED trigger and recurring interval of 7 days
|
||||||
- Workflow run date is 6 days ago
|
- Workflow run date is 6 days ago
|
||||||
|
- Document created 40 days ago, offset = 30 → trigger time = 10 days ago
|
||||||
WHEN:
|
WHEN:
|
||||||
- Scheduled workflows are checked
|
- Scheduled workflows are checked
|
||||||
THEN:
|
THEN:
|
||||||
@ -1600,6 +1610,58 @@ class TestWorkflows(
|
|||||||
doc.refresh_from_db()
|
doc.refresh_from_db()
|
||||||
self.assertIsNone(doc.owner)
|
self.assertIsNone(doc.owner)
|
||||||
|
|
||||||
|
def test_workflow_scheduled_trigger_negative_offset(self):
|
||||||
|
"""
|
||||||
|
GIVEN:
|
||||||
|
- Existing workflow with SCHEDULED trigger and negative offset of -7 days (so 7 days after date)
|
||||||
|
- Custom field date initially set to 5 days ago → trigger time = 2 days in future
|
||||||
|
- Then updated to 8 days ago → trigger time = 1 day ago
|
||||||
|
WHEN:
|
||||||
|
- Scheduled workflows are checked for document with custom field date 8 days in the past
|
||||||
|
THEN:
|
||||||
|
- Workflow runs and document owner is updated
|
||||||
|
"""
|
||||||
|
trigger = WorkflowTrigger.objects.create(
|
||||||
|
type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
|
||||||
|
schedule_offset_days=-7,
|
||||||
|
schedule_date_field=WorkflowTrigger.ScheduleDateField.CUSTOM_FIELD,
|
||||||
|
schedule_date_custom_field=self.cf1,
|
||||||
|
)
|
||||||
|
action = WorkflowAction.objects.create(
|
||||||
|
assign_title="Doc assign owner",
|
||||||
|
assign_owner=self.user2,
|
||||||
|
)
|
||||||
|
w = Workflow.objects.create(
|
||||||
|
name="Workflow 1",
|
||||||
|
order=0,
|
||||||
|
)
|
||||||
|
w.triggers.add(trigger)
|
||||||
|
w.actions.add(action)
|
||||||
|
w.save()
|
||||||
|
|
||||||
|
doc = Document.objects.create(
|
||||||
|
title="sample test",
|
||||||
|
correspondent=self.c,
|
||||||
|
original_filename="sample.pdf",
|
||||||
|
)
|
||||||
|
cfi = CustomFieldInstance.objects.create(
|
||||||
|
document=doc,
|
||||||
|
field=self.cf1,
|
||||||
|
value_date=timezone.now() - timedelta(days=5),
|
||||||
|
)
|
||||||
|
|
||||||
|
tasks.check_scheduled_workflows()
|
||||||
|
|
||||||
|
doc.refresh_from_db()
|
||||||
|
self.assertIsNone(doc.owner) # has not triggered yet
|
||||||
|
|
||||||
|
cfi.value_date = timezone.now() - timedelta(days=8)
|
||||||
|
cfi.save()
|
||||||
|
|
||||||
|
tasks.check_scheduled_workflows()
|
||||||
|
doc.refresh_from_db()
|
||||||
|
self.assertEqual(doc.owner, self.user2)
|
||||||
|
|
||||||
def test_workflow_enabled_disabled(self):
|
def test_workflow_enabled_disabled(self):
|
||||||
trigger = WorkflowTrigger.objects.create(
|
trigger = WorkflowTrigger.objects.create(
|
||||||
type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED,
|
type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED,
|
||||||
|
@ -2,7 +2,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: paperless-ngx\n"
|
"Project-Id-Version: paperless-ngx\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-04-23 16:31+0000\n"
|
"POT-Creation-Date: 2025-05-11 19:44+0000\n"
|
||||||
"PO-Revision-Date: 2022-02-17 04:17\n"
|
"PO-Revision-Date: 2022-02-17 04:17\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: English\n"
|
"Language-Team: English\n"
|
||||||
@ -1589,15 +1589,59 @@ msgstr ""
|
|||||||
msgid "Adds additional user arguments for OCRMyPDF"
|
msgid "Adds additional user arguments for OCRMyPDF"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:171
|
#: paperless/models.py:175
|
||||||
msgid "Application title"
|
msgid "Application title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:178
|
#: paperless/models.py:182
|
||||||
msgid "Application logo"
|
msgid "Application logo"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: paperless/models.py:188
|
#: paperless/models.py:197
|
||||||
|
msgid "Enables barcode scanning"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:203
|
||||||
|
msgid "Enables barcode TIFF support"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:209
|
||||||
|
msgid "Sets the barcode string"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:217
|
||||||
|
msgid "Retains split pages"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:223
|
||||||
|
msgid "Enables ASN barcode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:229
|
||||||
|
msgid "Sets the ASN barcode prefix"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:237
|
||||||
|
msgid "Sets the barcode upscale factor"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:244
|
||||||
|
msgid "Sets the barcode DPI"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:251
|
||||||
|
msgid "Sets the maximum pages for barcode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:258
|
||||||
|
msgid "Enables tag barcode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:264
|
||||||
|
msgid "Sets the tag barcode mapping"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: paperless/models.py:269
|
||||||
msgid "paperless application settings"
|
msgid "paperless application settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -96,10 +96,65 @@ class OcrConfig(OutputTypeConfig):
|
|||||||
user_args = json.loads(settings.OCR_USER_ARGS)
|
user_args = json.loads(settings.OCR_USER_ARGS)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
user_args = {}
|
user_args = {}
|
||||||
|
|
||||||
self.user_args = user_args
|
self.user_args = user_args
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class BarcodeConfig(BaseConfig):
|
||||||
|
"""
|
||||||
|
Barcodes settings
|
||||||
|
"""
|
||||||
|
|
||||||
|
barcodes_enabled: bool = dataclasses.field(init=False)
|
||||||
|
barcode_enable_tiff_support: bool = dataclasses.field(init=False)
|
||||||
|
barcode_string: str = dataclasses.field(init=False)
|
||||||
|
barcode_retain_split_pages: bool = dataclasses.field(init=False)
|
||||||
|
barcode_enable_asn: bool = dataclasses.field(init=False)
|
||||||
|
barcode_asn_prefix: str = dataclasses.field(init=False)
|
||||||
|
barcode_upscale: float = dataclasses.field(init=False)
|
||||||
|
barcode_dpi: int = dataclasses.field(init=False)
|
||||||
|
barcode_max_pages: int = dataclasses.field(init=False)
|
||||||
|
barcode_enable_tag: bool = dataclasses.field(init=False)
|
||||||
|
barcode_tag_mapping: dict[str, str] = dataclasses.field(init=False)
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
app_config = self._get_config_instance()
|
||||||
|
|
||||||
|
self.barcodes_enabled = (
|
||||||
|
app_config.barcodes_enabled or settings.CONSUMER_ENABLE_BARCODES
|
||||||
|
)
|
||||||
|
self.barcode_enable_tiff_support = (
|
||||||
|
app_config.barcode_enable_tiff_support
|
||||||
|
or settings.CONSUMER_BARCODE_TIFF_SUPPORT
|
||||||
|
)
|
||||||
|
self.barcode_string = (
|
||||||
|
app_config.barcode_string or settings.CONSUMER_BARCODE_STRING
|
||||||
|
)
|
||||||
|
self.barcode_retain_split_pages = (
|
||||||
|
app_config.barcode_retain_split_pages
|
||||||
|
or settings.CONSUMER_BARCODE_RETAIN_SPLIT_PAGES
|
||||||
|
)
|
||||||
|
self.barcode_enable_asn = (
|
||||||
|
app_config.barcode_enable_asn or settings.CONSUMER_ENABLE_ASN_BARCODE
|
||||||
|
)
|
||||||
|
self.barcode_asn_prefix = (
|
||||||
|
app_config.barcode_asn_prefix or settings.CONSUMER_ASN_BARCODE_PREFIX
|
||||||
|
)
|
||||||
|
self.barcode_upscale = (
|
||||||
|
app_config.barcode_upscale or settings.CONSUMER_BARCODE_UPSCALE
|
||||||
|
)
|
||||||
|
self.barcode_dpi = app_config.barcode_dpi or settings.CONSUMER_BARCODE_DPI
|
||||||
|
self.barcode_max_pages = (
|
||||||
|
app_config.barcode_max_pages or settings.CONSUMER_BARCODE_MAX_PAGES
|
||||||
|
)
|
||||||
|
self.barcode_enable_tag = (
|
||||||
|
app_config.barcode_enable_tag or settings.CONSUMER_ENABLE_TAG_BARCODE
|
||||||
|
)
|
||||||
|
self.barcode_tag_mapping = (
|
||||||
|
app_config.barcode_tag_mapping or settings.CONSUMER_TAG_BARCODE_MAPPING
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class GeneralConfig(BaseConfig):
|
class GeneralConfig(BaseConfig):
|
||||||
"""
|
"""
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-04-02 19:21
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("paperless", "0003_alter_applicationconfiguration_max_image_pixels"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_asn_prefix",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
max_length=32,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Sets the ASN barcode prefix",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_dpi",
|
||||||
|
field=models.PositiveIntegerField(
|
||||||
|
null=True,
|
||||||
|
validators=[django.core.validators.MinValueValidator(1)],
|
||||||
|
verbose_name="Sets the barcode DPI",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_enable_asn",
|
||||||
|
field=models.BooleanField(null=True, verbose_name="Enables ASN barcode"),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_enable_tag",
|
||||||
|
field=models.BooleanField(null=True, verbose_name="Enables tag barcode"),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_enable_tiff_support",
|
||||||
|
field=models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
verbose_name="Enables barcode TIFF support",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_max_pages",
|
||||||
|
field=models.PositiveIntegerField(
|
||||||
|
null=True,
|
||||||
|
validators=[django.core.validators.MinValueValidator(1)],
|
||||||
|
verbose_name="Sets the maximum pages for barcode",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_retain_split_pages",
|
||||||
|
field=models.BooleanField(null=True, verbose_name="Retains split pages"),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_string",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
max_length=32,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Sets the barcode string",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_tag_mapping",
|
||||||
|
field=models.JSONField(
|
||||||
|
null=True,
|
||||||
|
verbose_name="Sets the tag barcode mapping",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcode_upscale",
|
||||||
|
field=models.FloatField(
|
||||||
|
null=True,
|
||||||
|
validators=[django.core.validators.MinValueValidator(1.0)],
|
||||||
|
verbose_name="Sets the barcode upscale factor",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="applicationconfiguration",
|
||||||
|
name="barcodes_enabled",
|
||||||
|
field=models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
verbose_name="Enables barcode scanning",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -167,6 +167,10 @@ class ApplicationConfiguration(AbstractSingletonModel):
|
|||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Settings for the Paperless application
|
||||||
|
"""
|
||||||
|
|
||||||
app_title = models.CharField(
|
app_title = models.CharField(
|
||||||
verbose_name=_("Application title"),
|
verbose_name=_("Application title"),
|
||||||
null=True,
|
null=True,
|
||||||
@ -184,6 +188,83 @@ class ApplicationConfiguration(AbstractSingletonModel):
|
|||||||
upload_to="logo/",
|
upload_to="logo/",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Settings for the barcode scanner
|
||||||
|
"""
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_ENABLE_BARCODES
|
||||||
|
barcodes_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Enables barcode scanning"),
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_BARCODE_TIFF_SUPPORT
|
||||||
|
barcode_enable_tiff_support = models.BooleanField(
|
||||||
|
verbose_name=_("Enables barcode TIFF support"),
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_BARCODE_STRING
|
||||||
|
barcode_string = models.CharField(
|
||||||
|
verbose_name=_("Sets the barcode string"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
max_length=32,
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_BARCODE_RETAIN_SPLIT_PAGES
|
||||||
|
barcode_retain_split_pages = models.BooleanField(
|
||||||
|
verbose_name=_("Retains split pages"),
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE
|
||||||
|
barcode_enable_asn = models.BooleanField(
|
||||||
|
verbose_name=_("Enables ASN barcode"),
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_ASN_BARCODE_PREFIX
|
||||||
|
barcode_asn_prefix = models.CharField(
|
||||||
|
verbose_name=_("Sets the ASN barcode prefix"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
max_length=32,
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_BARCODE_UPSCALE
|
||||||
|
barcode_upscale = models.FloatField(
|
||||||
|
verbose_name=_("Sets the barcode upscale factor"),
|
||||||
|
null=True,
|
||||||
|
validators=[MinValueValidator(1.0)],
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_BARCODE_DPI
|
||||||
|
barcode_dpi = models.PositiveIntegerField(
|
||||||
|
verbose_name=_("Sets the barcode DPI"),
|
||||||
|
null=True,
|
||||||
|
validators=[MinValueValidator(1)],
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_BARCODE_MAX_PAGES
|
||||||
|
barcode_max_pages = models.PositiveIntegerField(
|
||||||
|
verbose_name=_("Sets the maximum pages for barcode"),
|
||||||
|
null=True,
|
||||||
|
validators=[MinValueValidator(1)],
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_ENABLE_TAG_BARCODE
|
||||||
|
barcode_enable_tag = models.BooleanField(
|
||||||
|
verbose_name=_("Enables tag barcode"),
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# PAPERLESS_CONSUMER_TAG_BARCODE_MAPPING
|
||||||
|
barcode_tag_mapping = models.JSONField(
|
||||||
|
verbose_name=_("Sets the tag barcode mapping"),
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("paperless application settings")
|
verbose_name = _("paperless application settings")
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ from allauth.mfa.adapter import get_adapter as get_mfa_adapter
|
|||||||
from allauth.mfa.models import Authenticator
|
from allauth.mfa.models import Authenticator
|
||||||
from allauth.mfa.totp.internal.auth import TOTP
|
from allauth.mfa.totp.internal.auth import TOTP
|
||||||
from allauth.socialaccount.models import SocialAccount
|
from allauth.socialaccount.models import SocialAccount
|
||||||
|
from allauth.socialaccount.models import SocialApp
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@ -146,8 +147,11 @@ class SocialAccountSerializer(serializers.ModelSerializer):
|
|||||||
"name",
|
"name",
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_name(self, obj) -> str:
|
def get_name(self, obj: SocialAccount) -> str:
|
||||||
return obj.get_provider_account().to_str()
|
try:
|
||||||
|
return obj.get_provider_account().to_str()
|
||||||
|
except SocialApp.DoesNotExist:
|
||||||
|
return "Unknown App"
|
||||||
|
|
||||||
|
|
||||||
class ProfileSerializer(serializers.ModelSerializer):
|
class ProfileSerializer(serializers.ModelSerializer):
|
||||||
@ -185,11 +189,14 @@ class ProfileSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class ApplicationConfigurationSerializer(serializers.ModelSerializer):
|
class ApplicationConfigurationSerializer(serializers.ModelSerializer):
|
||||||
user_args = serializers.JSONField(binary=True, allow_null=True)
|
user_args = serializers.JSONField(binary=True, allow_null=True)
|
||||||
|
barcode_tag_mapping = serializers.JSONField(binary=True, allow_null=True)
|
||||||
|
|
||||||
def run_validation(self, data):
|
def run_validation(self, data):
|
||||||
# Empty strings treated as None to avoid unexpected behavior
|
# Empty strings treated as None to avoid unexpected behavior
|
||||||
if "user_args" in data and data["user_args"] == "":
|
if "user_args" in data and data["user_args"] == "":
|
||||||
data["user_args"] = None
|
data["user_args"] = None
|
||||||
|
if "barcode_tag_mapping" in data and data["barcode_tag_mapping"] == "":
|
||||||
|
data["barcode_tag_mapping"] = None
|
||||||
if "language" in data and data["language"] == "":
|
if "language" in data and data["language"] == "":
|
||||||
data["language"] = None
|
data["language"] = None
|
||||||
return super().run_validation(data)
|
return super().run_validation(data)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user