Compare commits

...

222 Commits

Author SHA1 Message Date
shamoon
c754a5f391 Bumps version to 1.17.4 2023-09-01 13:29:55 -07:00
shamoon
2b692c6fc8 Merge branch 'dev' 2023-09-01 13:29:16 -07:00
Paperless-ngx Bot [bot]
35b6fb1a6d New translations messages.xlf (Greek) (#4095)
[ci skip]
2023-09-01 13:28:41 -07:00
shamoon
61566a34d1 Fix consumer error typo 2023-09-01 00:11:32 -07:00
shamoon
e14f4c94c2 Fix: ghostscript rendering error doesnt trigger frontend failure message (#4092)
* Raise ParseError from gs rendering error

* catch all parser errors as generic exception

* Differentiate generic vs parse errors during consumption
2023-08-31 19:49:00 -07:00
shamoon
8d35f22daf Merge pull request #4085 from paperless-ngx/v1.17.3-changelog
[Documentation] Add v1.17.3 changelog
2023-08-29 15:55:34 -07:00
Trenton H
6f8ef9bbdc Change the category of the pdf-js update 2023-08-29 11:53:59 -07:00
github-actions
e7ddf6ba8f Changelog v1.17.3 - GHA 2023-08-28 21:42:38 -07:00
shamoon
407a119b9a Fix long document names cause overflow on tasks view 2023-08-28 21:32:10 -07:00
shamoon
96aa2451bf Add Ghostscript error to troubleshooting docs 2023-08-28 19:29:36 -07:00
Trenton Holmes
7680aab04d Reset to -dev version string 2023-08-28 18:43:21 -07:00
Trenton Holmes
3aef26b229 Bumps version to 1.17.3 2023-08-28 18:28:40 -07:00
Trenton Holmes
935141adc0 Merge remote-tracking branch 'origin/dev' 2023-08-28 18:27:07 -07:00
Trenton Holmes
4300733d0c Fixes an erroneous raise that prevented the retry logic from going 2023-08-28 18:26:22 -07:00
Paperless-ngx Bot [bot]
c284a091c0 New Crowdin updates (#3997)
* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations django.po (Slovenian)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2023-08-28 18:17:51 -07:00
Trenton H
7e768bfe23 When PDF/A rendering fails, add a warning the user may want to allow it to continue 2023-08-28 18:10:11 -07:00
Trenton H
938f388a0b Upload frontend and backend coverage information together so codecov is less wrong with it's initial comment 2023-08-28 18:05:34 -07:00
shamoon
d22a6fb8ea Merge pull request #4065 from paperless-ngx/feature-update-pdf-viewer
Chore: update frontend PDF viewer (including pdf-js)
2023-08-27 13:50:55 -07:00
shamoon
11142e2f05 Update ng2-pdf-viewer (including pdf-js) to 10.0.0 2023-08-27 00:29:23 -07:00
Trenton Holmes
fe7fb488c0 Do some trickery to support Python 3.11 and mocking invalid module names 2023-08-25 08:44:09 -07:00
shamoon
0929c5086a Merge pull request #4064 from paperless-ngx/v1.17.2-changelog
[Documentation] Add v1.17.2 changelog
2023-08-24 12:53:21 -07:00
github-actions
eb3ed7719b Changelog v1.17.2 - GHA 2023-08-24 19:09:28 +00:00
Trenton H
6c19a0f8c7 Reset to -dev versioning string 2023-08-24 11:42:25 -07:00
Trenton H
a0ece589b0 Bumps version to 1.17.2 2023-08-24 11:38:17 -07:00
Trenton H
8165071edf Merge remote-tracking branch 'origin/dev' 2023-08-24 11:35:16 -07:00
shamoon
a667974378 Update settings.component.spec.ts 2023-08-24 00:21:06 -07:00
Trenton Holmes
fe1f88ce5d Sets the http timeouts equal to the task timeout, so it's either done or really done 2023-08-23 18:40:22 -07:00
shamoon
8f2715e437 Merge pull request #4014 from paperless-ngx/ui-perms-tweaks
Enhancement: disable / hide some UI buttons / elements if insufficient permissions, show errors
2023-08-23 10:28:37 -07:00
shamoon
57a3223c77 Merge branch 'dev' into ui-perms-tweaks 2023-08-23 08:48:42 -07:00
Trenton H
df82ac8ac4 Adjusts to use a different loading of certificates and updates the docs for it 2023-08-23 08:22:01 -07:00
Trenton H
16adddc803 Allow users to set a combined certificte and key file for additional certificates in the SSL context 2023-08-23 08:22:01 -07:00
shamoon
d1ae82c5c2 Merge pull request #4038 from paperless-ngx/fix/issue-4036
Fix: tag creation sometimes retained search text
2023-08-21 11:15:15 -07:00
shamoon
0098936347 Fix: tag creation sometimes retained search text 2023-08-20 16:18:34 -07:00
shamoon
17b85f6400 Merge pull request #4035 from brakhane/polling-note
docs: add note about polling when using double-sided collation
2023-08-20 11:04:45 -07:00
Dennis Brakhane
48be9c0fd1 docs: add note about polling when using double-sided collation 2023-08-20 19:51:14 +02:00
shamoon
ce36c2d0ea Merge pull request #4007 from paperless-ngx/fix/issue-4003
Fix: enforce permissions on bulk_edit operations
2023-08-18 06:37:08 -07:00
shamoon
06c63ef4a4 Disable / hide some UI buttons / elements if insufficient permissions 2023-08-17 20:34:19 -07:00
shamoon
03d93a7d6e Fix: enforce permissions on bulk_edit operations 2023-08-17 00:12:46 -07:00
amo13
a0005c8b3e Enhancement: Allow to set a prefix for keys and channels in redis (#3993) 2023-08-16 00:05:01 +00:00
shamoon
2220343c50 Merge pull request #3998 from paperless-ngx/v1.17.1-changelog
[Documentation] Add v1.17.1 changelog
2023-08-15 13:35:50 -07:00
github-actions
68fbed996f Changelog v1.17.1 - GHA 2023-08-15 16:00:47 +00:00
Trenton H
20a4d8949d Reset to -dev version string 2023-08-15 08:42:06 -07:00
Trenton H
1029ecfd49 Bumps version to 1.17.1 2023-08-15 08:38:52 -07:00
Trenton H
4de2a3b09e Merge remote-tracking branch 'origin/dev' 2023-08-15 08:38:11 -07:00
Paperless-ngx Bot [bot]
651407c88e New Crowdin updates (#3930)
* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations django.po (Turkish)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]
2023-08-15 08:32:03 -07:00
shamoon
3e2e485f66 Update playwright 2023-08-14 21:51:46 -07:00
shamoon
10efaad224 Merge pull request #3988 from paperless-ngx/fix/issue-3986 2023-08-12 17:27:34 -07:00
shamoon
3dda02660c Implement isNumber pipe 2023-08-12 08:31:42 -07:00
shamoon
0b4e8141b0 Merge pull request #3980 from paperless-ngx/fix/issue-3978
Fix: improve light color filled primary button text legibility
2023-08-11 20:03:46 -07:00
shamoon
16ab0efa59 Merge branch 'dev' into fix/issue-3978 2023-08-11 07:49:44 -07:00
shamoon
20ca1ec547 Merge pull request #3979 from paperless-ngx/fix/ukrainian-spelling
Fix: Correct spelling of Ukrainian
2023-08-11 07:49:33 -07:00
shamoon
a1c9ab237f Fix light color filled primary button text legibility 2023-08-11 07:43:41 -07:00
shamoon
a65239f7f1 Correct spelling of Ukrainian 2023-08-11 07:25:31 -07:00
Trenton H
a0622675fd Loosen restriction and update a couple of packages which were out of date 2023-08-10 17:23:16 -07:00
shamoon
1e0b778097 Merge pull request #3959 from paperless-ngx/fix/issue-3945
Fix: restrict status messages by owner if set
2023-08-09 17:52:47 -07:00
shamoon
3b666fef77 Add backend check for ws message ownership 2023-08-09 16:46:48 -07:00
shamoon
9291c98189 Improve 404 navigation and styling 2023-08-09 00:30:20 -07:00
shamoon
f6dadd8c82 Merge branch 'dev' into fix/issue-3945 2023-08-08 22:37:13 -07:00
shamoon
022bb272e6 Restrict status messages by owner if set 2023-08-08 20:39:55 -07:00
shamoon
edad1a41e8 Merge pull request #3953 from paperless-ngx/fix/issue-3944
Handle very old date strings in correspondent list
2023-08-08 06:59:29 -07:00
shamoon
421e78a748 Handle very old date strings in correspondent list 2023-08-07 17:31:38 -07:00
Trenton H
b961df90a7 Reduces the 2 mail tests flakiness 2023-08-07 15:32:33 -07:00
shamoon
0b26b7098a Merge pull request #3941 from paperless-ngx/feature-ukranian-translation
Feature: Add Ukranian translation
2023-08-06 08:20:32 -07:00
shamoon
b09566a9a9 Adds Ukranian translation 2023-08-06 08:08:07 -07:00
github-actions
b869deab66 Changelog v1.17.0 - GHA 2023-08-05 09:17:18 -07:00
Jens van Almsick
3d552c3112 docs(bare-metal): add new dependency
mysqlclient 2.2.0 now requires pkg-config during installation via pip see https://github.com/PyMySQL/mysqlclient/discussions/638#discussioncomment-6333394
2023-08-05 07:55:18 -07:00
shamoon
2a2bf3bf55 Update environment.prod.ts 2023-08-04 12:04:36 -07:00
shamoon
26863b8cdc Bumps version to 1.17.0 2023-08-04 11:39:14 -07:00
shamoon
b0f7d07214 Merge branch 'dev' 2023-08-04 11:38:12 -07:00
Paperless-ngx Bot [bot]
30c6557a32 New Crowdin updates (#3742)
* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations django.po (Portuguese)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations django.po (Norwegian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations django.po (Hebrew)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations django.po (Hungarian)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations django.po (Italian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations django.po (Swedish)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations django.po (Hungarian)
[ci skip]

* New translations django.po (Hungarian)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations django.po (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations django.po (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations django.po (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations django.po (Croatian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations django.po (Croatian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations django.po (Ukrainian)
[ci skip]

* New translations messages.xlf (Ukrainian)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2023-08-04 18:37:15 +00:00
shamoon
e18e173089 Update messages.xlf 2023-08-04 11:25:22 -07:00
shamoon
6a8bdbd4f6 Merge pull request #3925 from paperless-ngx/fix/cancel-slow-queries 2023-08-04 07:22:23 -07:00
shamoon
b5dec87a62 Cancel possibly slow queries on leave doc details 2023-08-03 21:49:11 -07:00
Trenton H
e50d30876a Merge pull request #3760 from a17t/dev
[BUG] Set office document creation date with timezone, if it is naive
2023-08-03 10:35:56 -07:00
Trenton Holmes
cbcd9ed67d Merge remote-tracking branch 'paperless-ngx/dev' into dev 2023-08-03 10:00:14 -07:00
Trenton Holmes
6bcc26b487 Sets the timezone of creation, if the date is known and naive 2023-08-03 09:57:52 -07:00
Simon Siebert
56fcb3fee1 Working arround current TIKA Library Bugs - lint 2023-08-03 09:55:10 -07:00
shamoon
557e1790dd Merge pull request #3903 from paperless-ngx/fix/issue-3902
Fix: note creation / deletion should respect doc permissions
2023-08-02 08:33:44 -07:00
shamoon
2e67697d36 Note creation / deletion should respect doc permissions
- Disable add note button on frontend
- Explicitly disable add / delete via api
2023-08-01 22:28:27 -07:00
shamoon
ca4500692f remove unused e2e code 2023-08-01 19:27:52 -07:00
shamoon
5aba6bff09 Merge pull request #3918 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/frontend-angular-dependencies-f0885b8c36
Chore: Bump the frontend-angular-dependencies group in /src-ui with 11 updates
2023-08-01 19:27:23 -07:00
shamoon
9ed74068b9 Merge branch 'dev' into dependabot/npm_and_yarn/src-ui/dev/frontend-angular-dependencies-f0885b8c36 2023-08-01 19:27:11 -07:00
shamoon
be4685742c remove redundant e2e tests 2023-08-01 19:23:11 -07:00
dependabot[bot]
86b0a38811 Bump the frontend-angular-dependencies group in /src-ui with 11 updates
Bumps the frontend-angular-dependencies group in /src-ui with 11 updates:

| Package | Update |
| --- | --- |
| [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | 16.1.5 to 16.1.7 |
| [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | 16.1.5 to 16.1.7 |
| [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | 16.1.5 to 16.1.7 |
| [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) | 16.1.5 to 16.1.7 |
| [@angular/localize](https://github.com/angular/angular) | 16.1.5 to 16.1.7 |
| [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | 16.1.5 to 16.1.7 |
| [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) | 16.1.5 to 16.1.7 |
| [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | 16.1.5 to 16.1.7 |
| [@ng-select/ng-select](https://github.com/ng-select/ng-select) | 11.0.0 to 11.1.1 |
| [@angular-devkit/build-angular](https://github.com/angular/angular-cli) | 16.1.4 to 16.1.6 |
| [@angular/cli](https://github.com/angular/angular-cli) | 16.1.4 to 16.1.6 |


Updates `@angular/common` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.7/packages/common)

Updates `@angular/compiler` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.7/packages/compiler)

Updates `@angular/core` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.7/packages/core)

Updates `@angular/forms` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.7/packages/forms)

Updates `@angular/localize` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/compare/16.1.5...16.1.7)

Updates `@angular/platform-browser` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.7/packages/platform-browser)

Updates `@angular/platform-browser-dynamic` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.7/packages/platform-browser-dynamic)

Updates `@angular/router` from 16.1.5 to 16.1.7
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.7/packages/router)

Updates `@ng-select/ng-select` from 11.0.0 to 11.1.1
- [Release notes](https://github.com/ng-select/ng-select/releases)
- [Changelog](https://github.com/ng-select/ng-select/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ng-select/ng-select/compare/v11.0.0...v11.1.1)

Updates `@angular-devkit/build-angular` from 16.1.4 to 16.1.6
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/16.1.4...16.1.6)

Updates `@angular/cli` from 16.1.4 to 16.1.6
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/16.1.4...16.1.6)

---
updated-dependencies:
- dependency-name: "@angular/common"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/compiler"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/forms"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/localize"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser-dynamic"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/router"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@ng-select/ng-select"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular-devkit/build-angular"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/cli"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-02 02:04:39 +00:00
dependabot[bot]
3e528f0a9a Bump stumpylog/image-cleaner-action from 0.1.0 to 0.2.0
Bumps [stumpylog/image-cleaner-action](https://github.com/stumpylog/image-cleaner-action) from 0.1.0 to 0.2.0.
- [Release notes](https://github.com/stumpylog/image-cleaner-action/releases)
- [Changelog](https://github.com/stumpylog/image-cleaner-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stumpylog/image-cleaner-action/compare/v0.1.0...v0.2.0)

---
updated-dependencies:
- dependency-name: stumpylog/image-cleaner-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 17:33:43 -07:00
shamoon
170d7b6922 Merge pull request #3911 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/frontend-eslint-dependencies-a4ef7a9a8b
Bump the frontend-eslint-dependencies group in /src-ui with 3 updates
2023-08-01 16:25:51 -07:00
dependabot[bot]
f05249a9ad Bump the frontend-eslint-dependencies group in /src-ui with 3 updates
Bumps the frontend-eslint-dependencies group in /src-ui with 3 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [eslint](https://github.com/eslint/eslint).


Updates `@typescript-eslint/eslint-plugin` from 6.1.0 to 6.2.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.2.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 6.1.0 to 6.2.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.2.1/packages/parser)

Updates `eslint` from 8.44.0 to 8.46.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.44.0...v8.46.0)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-eslint-dependencies
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-eslint-dependencies
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-eslint-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 23:14:30 +00:00
shamoon
5957ed7af3 Merge pull request #3909 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/tslib-2.6.1
Bump tslib from 2.6.0 to 2.6.1 in /src-ui
2023-08-01 16:12:29 -07:00
shamoon
8ed63893eb Merge branch 'dev' into dependabot/npm_and_yarn/src-ui/dev/tslib-2.6.1 2023-08-01 15:37:47 -07:00
shamoon
ea9dd926bc Merge pull request #3916 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/jest-environment-jsdom-29.6.2
Bump jest-environment-jsdom from 29.5.0 to 29.6.2 in /src-ui
2023-08-01 15:35:40 -07:00
dependabot[bot]
f31d3b531f Bump jest-environment-jsdom from 29.5.0 to 29.6.2 in /src-ui
Bumps [jest-environment-jsdom](https://github.com/facebook/jest/tree/HEAD/packages/jest-environment-jsdom) from 29.5.0 to 29.6.2.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.6.2/packages/jest-environment-jsdom)

---
updated-dependencies:
- dependency-name: jest-environment-jsdom
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 22:17:56 +00:00
shamoon
d851448c32 Merge pull request #3915 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/types/node-20.4.5
Bump @types/node from 20.3.3 to 20.4.5 in /src-ui
2023-08-01 15:17:02 -07:00
shamoon
65327d52a6 Merge branch 'dev' into dependabot/npm_and_yarn/src-ui/dev/tslib-2.6.1 2023-08-01 15:06:07 -07:00
dependabot[bot]
2ea5ae59b2 Bump @types/node from 20.3.3 to 20.4.5 in /src-ui
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.3.3 to 20.4.5.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 22:03:07 +00:00
shamoon
a04d09028b Merge pull request #3914 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/bootstrap-5.3.1
Bump bootstrap from 5.3.0 to 5.3.1 in /src-ui
2023-08-01 15:02:11 -07:00
dependabot[bot]
dd9255cb81 Bump bootstrap from 5.3.0 to 5.3.1 in /src-ui
Bumps [bootstrap](https://github.com/twbs/bootstrap) from 5.3.0 to 5.3.1.
- [Release notes](https://github.com/twbs/bootstrap/releases)
- [Commits](https://github.com/twbs/bootstrap/compare/v5.3.0...v5.3.1)

---
updated-dependencies:
- dependency-name: bootstrap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 21:35:01 +00:00
shamoon
536d7ecd3e Merge pull request #3912 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/playwright/test-1.36.2
Bump @playwright/test from 1.36.1 to 1.36.2 in /src-ui
2023-08-01 14:33:42 -07:00
shamoon
f50aac08df Merge branch 'dev' into dependabot/npm_and_yarn/src-ui/dev/tslib-2.6.1 2023-08-01 14:02:26 -07:00
dependabot[bot]
db0f1d2159 Bump @playwright/test from 1.36.1 to 1.36.2 in /src-ui
Bumps [@playwright/test](https://github.com/Microsoft/playwright) from 1.36.1 to 1.36.2.
- [Release notes](https://github.com/Microsoft/playwright/releases)
- [Commits](https://github.com/Microsoft/playwright/compare/v1.36.1...v1.36.2)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 21:02:21 +00:00
shamoon
d97b565d6c Merge pull request #3906 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/frontend-jest-dependencies-7b2ae8246b
Bump the frontend-jest-dependencies group in /src-ui with 1 update
2023-08-01 14:01:26 -07:00
shamoon
d3071f13d8 Merge branch 'dev' into dependabot/npm_and_yarn/src-ui/dev/tslib-2.6.1 2023-08-01 13:48:39 -07:00
dependabot[bot]
768407c1d7 Bump the frontend-jest-dependencies group in /src-ui with 1 update
Bumps the frontend-jest-dependencies group in /src-ui with 1 update: [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest).

- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.6.2/packages/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-jest-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 20:28:34 +00:00
shamoon
c5d18b03cd Add eslint to eslint dependabot group 2023-08-01 13:27:58 -07:00
shamoon
5f05b44cde Merge pull request #3904 from paperless-ngx/fix/notes-scrollbars
Fix: notes show persistent scrollbars
2023-08-01 13:25:16 -07:00
dependabot[bot]
beaa09e9b3 Bump tslib from 2.6.0 to 2.6.1 in /src-ui
Bumps [tslib](https://github.com/Microsoft/tslib) from 2.6.0 to 2.6.1.
- [Release notes](https://github.com/Microsoft/tslib/releases)
- [Commits](https://github.com/Microsoft/tslib/compare/2.6.0...v2.6.1)

---
updated-dependencies:
- dependency-name: tslib
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 20:14:35 +00:00
shamoon
d6960f537b Do not force scroll on notes .card-body 2023-08-01 09:14:32 -07:00
brainrecursion
0918eab004 Remove debug 2023-07-30 08:34:33 -07:00
brainrecursion
9b16789a17 Add additional test for date parsing 2023-07-30 08:34:33 -07:00
brainrecursion
157240351f Add support for more date formats 2023-07-30 08:34:33 -07:00
mechanarchy
6ad3d45d60 Add 'doc_pk' to PAPERLESS_FILENAME_FORMAT handling (#3861)
* Add 'doc_pk' to PAPERLESS_FILENAME_FORMAT handling

* Add test for 'doc_pk' filename formatter
2023-07-30 08:30:50 -07:00
Trenton H
b715e4d426 Creates and provides a default SSL context to the IMAP library 2023-07-28 10:43:37 -07:00
Trenton H
aad5e9e99f Locks and upgrades all dependencies 2023-07-27 12:30:41 -07:00
shamoon
2a104ad33f Merge pull request #3875 from paperless-ngx/feature-widget-buttons 2023-07-27 12:20:20 -07:00
shamoon
851290ee89 Merge branch 'dev' into feature-widget-buttons 2023-07-27 11:49:17 -07:00
shamoon
a8c6c55e3b Useful buttons for saved view widgets 2023-07-26 11:36:55 -07:00
shamoon
992a647424 Fix large card date hover text color 2023-07-26 11:31:37 -07:00
shamoon
c22461a1b6 Merge pull request #3869 from paperless-ngx/fix/issue-3868
Fix/enhancement: permissions for mail rules & accounts
2023-07-26 07:37:54 -07:00
shamoon
23fefc3ab7 Include permissions for mail rules & accounts 2023-07-26 07:28:25 -07:00
shamoon
0beb9f0b5f Update frontend consumer status phases 2023-07-26 07:03:43 -07:00
Trenton Holmes
d376f9e7a3 Adding more typing around the classification and matching 2023-07-26 07:03:43 -07:00
Trenton Holmes
07e7bcd30b Small improvement to the consumer status with stronger typing 2023-07-26 07:03:43 -07:00
shamoon
95e86cb649 Add tip about permissions behavior 2023-07-25 13:27:50 -07:00
Trenton H
802e5591ce Also handles confirming returned predictions are still automatic matching, in case the classifier hasn't been run since a type was changed 2023-07-24 12:31:56 -07:00
Trenton H
26d5730ad2 Handles a special case where the classification model exists, but no items are auto matching any longer 2023-07-24 12:31:56 -07:00
Dennis Brakhane
8c7554e081 Feature: collate two single-sided multipage scans (#3784)
* Feature: collate two single-sided scans

Some ADF only support single-sided scans, making scanning
double-sided documents a bit annoying.

This new feature enables Paperless to do most of the work,
by merging two seperate scans into a single one, collating
the even and odd numbered pages.

* Documentation: clarify that collation is disabled by default

* Apply suggestions from code review

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>

* Address code review remarks

* Grammar fixes

---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2023-07-24 00:29:04 -07:00
Trenton H
9f5d47c320 Fixes issues with copy2 or copystat and SELinux see #3665 2023-07-22 06:27:49 -07:00
shamoon
4aa452ce63 Merge pull request #3844 from mechanarchy/patch-1
Documentation improvements
2023-07-21 10:26:51 -07:00
mechanarchy
7ef81ae10f Updates documentation formatting, grammar, links
Correct indentation of lists, code blocks

Update faq.md

Update CONTRIBUTING.md

Update development.md

Update advanced_usage.md

Update administration.md

Update configuration.md

Update configuration.md

Update advanced_usage.md

Update faq.md
2023-07-21 10:17:57 -07:00
shamoon
3628292afa Updates frontend strings from latest prettier changes 2023-07-20 18:30:11 -07:00
Trenton H
8aa5ecde62 Updates some Python dependencies and the hooks 2023-07-20 18:30:11 -07:00
shamoon
2f149eac9d Merge pull request #3672 from paperless-ngx/feature-permissions-exportimport
Feature: include global and object-level permissions in export / import
2023-07-20 11:40:53 -07:00
Trenton H
fcfc705b87 Fixes the timezone value in a test 2023-07-20 07:01:38 -07:00
Trenton H
7bd5c010a1 Updates to latest tika-client 2023-07-20 07:01:38 -07:00
shamoon
52168d8e61 Merge pull request #3835 from paperless-ngx/fix/issue-3833
Fix: Add warning to install script need for permissions
2023-07-19 18:16:08 -07:00
Trenton H
a3842d9228 Fixes the barcode setting always overriding the ASN, even if one wasn't found 2023-07-19 18:10:38 -07:00
shamoon
452c51bd16 Add warning to install script need for permissions 2023-07-19 16:03:35 -07:00
dependabot[bot]
22bedd9957 Merge pull request #3826 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/frontend-angular-dependencies-33417c6be4 2023-07-19 18:09:56 +00:00
dependabot[bot]
cb318c723d Bump the frontend-angular-dependencies group in /src-ui with 16 updates
Bumps the frontend-angular-dependencies group in /src-ui with 16 updates:

| Package | Update |
| --- | --- |
| [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | 16.1.3 to 16.1.5 |
| [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | 16.1.3 to 16.1.5 |
| [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | 16.1.3 to 16.1.5 |
| [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) | 16.1.3 to 16.1.5 |
| [@angular/localize](https://github.com/angular/angular) | 16.1.3 to 16.1.5 |
| [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | 16.1.3 to 16.1.5 |
| [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) | 16.1.3 to 16.1.5 |
| [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | 16.1.3 to 16.1.5 |
| [@ng-bootstrap/ng-bootstrap](https://github.com/ng-bootstrap/ng-bootstrap) | 15.0.1 to 15.1.0 |
| [@angular-devkit/build-angular](https://github.com/angular/angular-cli) | 16.1.3 to 16.1.4 |
| [@angular-eslint/builder](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/builder) | 16.0.3 to 16.1.0 |
| [@angular-eslint/eslint-plugin](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/eslint-plugin) | 16.0.3 to 16.1.0 |
| [@angular-eslint/eslint-plugin-template](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/eslint-plugin-template) | 16.0.3 to 16.1.0 |
| [@angular-eslint/schematics](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/schematics) | 16.0.3 to 16.1.0 |
| [@angular-eslint/template-parser](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/template-parser) | 16.0.3 to 16.1.0 |
| [@angular/cli](https://github.com/angular/angular-cli) | 16.1.3 to 16.1.4 |


Updates `@angular/common` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.5/packages/common)

Updates `@angular/compiler` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.5/packages/compiler)

Updates `@angular/core` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.5/packages/core)

Updates `@angular/forms` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.5/packages/forms)

Updates `@angular/localize` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/compare/16.1.3...16.1.5)

Updates `@angular/platform-browser` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.5/packages/platform-browser)

Updates `@angular/platform-browser-dynamic` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.5/packages/platform-browser-dynamic)

Updates `@angular/router` from 16.1.3 to 16.1.5
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/16.1.5/packages/router)

Updates `@ng-bootstrap/ng-bootstrap` from 15.0.1 to 15.1.0
- [Release notes](https://github.com/ng-bootstrap/ng-bootstrap/releases)
- [Changelog](https://github.com/ng-bootstrap/ng-bootstrap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ng-bootstrap/ng-bootstrap/compare/15.0.1...15.1.0)

Updates `@angular-devkit/build-angular` from 16.1.3 to 16.1.4
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/16.1.3...16.1.4)

Updates `@angular-eslint/builder` from 16.0.3 to 16.1.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/builder/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v16.1.0/packages/builder)

Updates `@angular-eslint/eslint-plugin` from 16.0.3 to 16.1.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v16.1.0/packages/eslint-plugin)

Updates `@angular-eslint/eslint-plugin-template` from 16.0.3 to 16.1.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v16.1.0/packages/eslint-plugin-template)

Updates `@angular-eslint/schematics` from 16.0.3 to 16.1.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/schematics/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v16.1.0/packages/schematics)

Updates `@angular-eslint/template-parser` from 16.0.3 to 16.1.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/template-parser/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v16.1.0/packages/template-parser)

Updates `@angular/cli` from 16.1.3 to 16.1.4
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/16.1.3...16.1.4)

---
updated-dependencies:
- dependency-name: "@angular/common"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/compiler"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/forms"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/localize"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser-dynamic"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/router"
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@ng-bootstrap/ng-bootstrap"
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular-devkit/build-angular"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular-eslint/builder"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular-eslint/eslint-plugin-template"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular-eslint/schematics"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular-eslint/template-parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/cli"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-19 17:47:16 +00:00
shamoon
9a81d3c28e Merge pull request #3719 from paperless-ngx/fix/issue-3712
Enhancement / Fix: Migrate encrypted png thumbnails to webp
2023-07-19 10:33:46 -07:00
dependabot[bot]
3ca59e3b7a Bump @typescript-eslint/eslint-plugin from 5.60.1 to 6.1.0 in /src-ui (#3829) 2023-07-19 17:28:31 +00:00
dependabot[bot]
07a12bdf15 Merge pull request #3828 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/jest-and-types/jest-29.6.1 2023-07-19 16:54:02 +00:00
shamoon
62e81d8bf0 Add more frontend dependabot groups 2023-07-19 09:48:23 -07:00
dependabot[bot]
e295a41caa Bump jest and @types/jest in /src-ui
Bumps [jest](https://github.com/facebook/jest/tree/HEAD/packages/jest) and [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest). These dependencies needed to be updated together.

Updates `jest` from 29.5.0 to 29.6.1
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v29.6.1/packages/jest)

Updates `@types/jest` from 29.5.2 to 29.5.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-19 16:33:43 +00:00
dependabot[bot]
c545a80aa3 Merge pull request #3827 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/playwright/test-1.36.1 2023-07-19 16:32:22 +00:00
dependabot[bot]
56f1a0cb51 Bump @playwright/test from 1.36.0 to 1.36.1 in /src-ui
Bumps [@playwright/test](https://github.com/Microsoft/playwright) from 1.36.0 to 1.36.1.
- [Release notes](https://github.com/Microsoft/playwright/releases)
- [Commits](https://github.com/Microsoft/playwright/compare/v1.36.0...v1.36.1)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-19 16:19:47 +00:00
shamoon
7218b6da97 Merge pull request #3750 from paperless-ngx/chore/frontend-angular-grouped-dependabot
Chore: group frontend angular dependabot updates
2023-07-19 09:13:50 -07:00
shamoon
83f9f2d387 Merge pull request #3793 from paperless-ngx/dependabot/npm_and_yarn/src-ui/semver-5.7.2
Bump semver from 5.7.1 to 5.7.2 in /src-ui
2023-07-13 09:26:41 -07:00
dependabot[bot]
13a2e38385 Bump semver from 5.7.1 to 5.7.2 in /src-ui
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-13 15:51:18 +00:00
shamoon
996d942387 Merge pull request #3794 from paperless-ngx/fix/playwright-1.36
Fix: Bumps playwright to 1.36.0
2023-07-13 08:50:28 -07:00
shamoon
cc42eb9fab Bumps playwright to 1.36.0 2023-07-13 08:18:00 -07:00
shamoon
44125be979 Merge pull request #3791 from hakimio/ui-tour-fix
Enhancement: add UI tour step padding
2023-07-13 08:08:17 -07:00
Tomas Rimkus
c2e9cc9a51 UI tour fixes and improvements
Update UI tour library
Fix popover padding in tour steps
Add 10px backdrop offset where needed
Refactor tour initialization to use defaults
Make popover-body rule more specific
Update messages.xlf
2023-07-13 07:58:41 -07:00
shamoon
fcd10f2adc Merge pull request #3783 from brakhane/ocr_test_fix
Tolerate improved tesseract results in ocr tests
2023-07-11 08:17:16 -07:00
Dennis Brakhane
93009c1eed Don't consider better OCR as failing
Tesseract 5.3.0 does a better job at OCR, and correctly
reads "a webp" instead of "awebp", this is good, so we
don't want the test to fail.
2023-07-11 16:44:18 +02:00
Simon Siebert
d875be60d4 Working arround current TIKA Library Bugs 2023-07-06 23:26:01 +02:00
shamoon
db48d4c576 Merge pull request #3749 from paperless-ngx/fix/issue-3747
Fix: translate file tasks types in footer
2023-07-05 10:14:37 -07:00
shamoon
3293231ad2 Merge pull request #3722 from paperless-ngx/feature-slovak-translation
Feature: Add Slovak translation
2023-07-05 09:59:12 -07:00
shamoon
aa1f2d3b59 Group frontend angular dependabot updates 2023-07-05 09:57:44 -07:00
shamoon
f492b679e3 Translate file tasks types in footer 2023-07-05 09:39:44 -07:00
shamoon
7ca84322bd Update messages.xlf 2023-07-05 09:39:36 -07:00
shamoon
e3257b8fa3 Merge pull request #3731 from paperless-ngx/fix/issue-3730
Fix: limit ng-select size for addition of filter button
2023-07-02 08:12:17 -07:00
shamoon
0bcda5ded8 Limit ng-select size for addition of filter button 2023-07-02 07:50:26 -07:00
shamoon
7ec82c0891 Merge pull request #3727 from paperless-ngx/dependabot/npm_and_yarn/src-ui/dev/angular/cli-16.1.3
Bump Angular to v16 and required packages
2023-07-01 21:42:12 -07:00
shamoon
3241ac7dc2 Upgrade to Angular 16
update ngx-file-drop
Update ng-bootstrap, ng-select, cookie-service and ui-tour
Update setup-jest.ts
bump typescript to 5.1.6

bump ngx-color and tslib
2023-07-01 19:59:24 -07:00
dependabot[bot]
e974605fc8 Bump @angular/cli from 15.2.7 to 16.1.3 in /src-ui
Bumps [@angular/cli](https://github.com/angular/angular-cli) from 15.2.7 to 16.1.3.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/15.2.7...16.1.3)

---
updated-dependencies:
- dependency-name: "@angular/cli"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 20:35:06 +00:00
shamoon
ce13380533 Add Slovak translation 2023-06-30 20:24:22 -07:00
Paperless-ngx Bot [bot]
e23e3acda3 New Crowdin updates (#3711)
* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations django.po (Slovak)
[ci skip]

* New translations django.po (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]
2023-06-30 19:59:22 -07:00
shamoon
63ab9972da Fixes tests broken by #3721 2023-06-30 08:36:47 -07:00
shamoon
feb4901620 Merge pull request #3721 from andreasbrett/patch-1
fixed typo in signals.pay log output
2023-06-30 07:52:14 -07:00
Andreas Brett
67788a1b1b fixed typo
full stop should be outside of the quoted IP address
2023-06-30 15:11:14 +02:00
shamoon
001faf9ed7 Migrate encrypted png thumbnails to webp 2023-06-29 13:21:15 -07:00
shamoon
7a464d8a6e Update dev version string 2023-06-27 16:44:05 -07:00
shamoon
5acd1c7c1b Merge pull request #3710 from paperless-ngx/v1.16.5-changelog
[Documentation] Add v1.16.5 changelog
2023-06-27 16:14:27 -07:00
github-actions
de14540374 Changelog v1.16.5 - GHA 2023-06-27 23:10:02 +00:00
shamoon
37e0c2667b Bumps version to 1.16.5 2023-06-27 14:51:49 -07:00
shamoon
252abb41c3 Merge branch 'dev' 2023-06-27 14:51:08 -07:00
shamoon
fb2af341d8 Adding explicit doc permissions test 2023-06-27 10:53:48 -07:00
Bastian Machek
931f5f9c27 Feature: support barcode upscaling for better detection of small barcodes (#3655) 2023-06-27 10:18:47 -07:00
shamoon
b5d04e575e Merge pull request #3702 from paperless-ngx/fix/issue-3347
Fix: owner removed when set_permissions passed on object create
2023-06-27 07:17:01 -07:00
shamoon
3d395601fe Fix owner removed when set_permissions passed 2023-06-27 01:41:20 -07:00
shamoon
6630ce646c Merge pull request #3699 from paperless-ngx/v1.16.4-changelog
[Documentation] Add v1.16.4 changelog
2023-06-26 14:25:17 -07:00
shamoon
f5508eea1c Update dev version string 2023-06-26 12:56:47 -07:00
github-actions
c8c460432f Changelog v1.16.4 - GHA 2023-06-26 18:43:20 +00:00
shamoon
18299dafd2 Bumps version to 1.16.4 2023-06-26 11:25:18 -07:00
shamoon
817d09026e Merge branch 'dev' 2023-06-26 11:24:04 -07:00
Paperless-ngx Bot [bot]
d76b009390 New Crowdin updates (#3698)
* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]

* New translations messages.xlf (Greek)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]
2023-06-26 11:23:42 -07:00
shamoon
9effed3ce1 Update messages.xlf 2023-06-26 11:21:20 -07:00
shamoon
c1bbfc5dcf Update api.md 2023-06-26 10:08:21 -07:00
shamoon
b6c9cfb76f Merge pull request #3697 from paperless-ngx/docs/update-api-perms-docs
Documentation: update API docs re permissions
2023-06-26 10:06:05 -07:00
shamoon
59ca7bbcf2 Update API docs re permissions 2023-06-26 10:03:44 -07:00
Paperless-ngx Bot [bot]
52c8d5e999 New translations messages.xlf (Spanish) (#3659)
[ci skip]
2023-06-26 09:58:12 -07:00
shamoon
5851e7f1b7 Merge pull request #3682 from paperless-ngx/fix/issue-3679
Fix: prevent button wrapping when sidebar narrows in MS Edge
2023-06-26 09:43:20 -07:00
Trenton H
e05b3441de Updates tika client library and handle the changes to it 2023-06-26 10:41:05 -06:00
Trenton H
0d6e79cb93 Fixes generation of thumbnails when the archive file hasn't already been created 2023-06-26 10:36:50 -06:00
shamoon
76a102d901 Prevent button wrapping 2023-06-25 07:25:07 -07:00
shamoon
bbd4659fbf Include global and object-level permissions in export / import
adds test for transaction
2023-06-23 23:33:36 -07:00
shamoon
0880420ef6 Merge pull request #3662 from kleinweby/fix-filter-row-gap
Fix: Use row gap for filter editor
2023-06-22 11:15:26 -07:00
Christian Speich
2351c79282 Use row gap for filter editor
Fixes other indentation in filter-editor
2023-06-22 11:13:17 -07:00
shamoon
d6016fc798 Update PULL_REQUEST_TEMPLATE.md 2023-06-22 09:46:18 -07:00
github-actions[bot]
bc17291006 Changelog v1.16.3 - GHA (#3661)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-06-22 09:42:36 -07:00
Trenton H
ed6cb14c4d Updates codecov configuration for the flag settings and notification interaction 2023-06-22 08:20:04 -07:00
Trenton Holmes
08de8a04b8 Resets -dev versioning 2023-06-22 06:34:51 -07:00
Trenton Holmes
5c67de8b47 Bumps version to 1.16.3 2023-06-22 06:32:25 -07:00
Paperless-ngx Bot [bot]
38b0408b1a New Crowdin updates (#3654)
* New translations messages.xlf (Spanish)
[ci skip]

* New translations django.po (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations django.po (Chinese Simplified)
[ci skip]
2023-06-21 21:02:14 -07:00
shamoon
9ccad7ea86 Fix date component incorrect translation unit 2023-06-21 20:59:29 -07:00
shamoon
4a4e810a14 Fix invalid translation unit 2023-06-21 20:40:29 -07:00
Trenton H
76d2df3bde Resets frontend version tag to -dev 2023-06-21 09:50:50 -07:00
Trenton H
c02563d894 Bumps version to 1.16.3 2023-06-21 09:49:36 -07:00
Trenton H
574ec6780b Merge remote-tracking branch 'origin/dev' 2023-06-21 09:48:33 -07:00
Paperless-ngx Bot [bot]
9e0f56982b New Crowdin updates (#3529)
* New translations messages.xlf (French)
[ci skip]

* New translations messages.xlf (Spanish)
[ci skip]

* New translations messages.xlf (Arabic)
[ci skip]

* New translations messages.xlf (Belarusian)
[ci skip]

* New translations messages.xlf (Catalan)
[ci skip]

* New translations messages.xlf (Czech)
[ci skip]

* New translations messages.xlf (Danish)
[ci skip]

* New translations messages.xlf (German)
[ci skip]

* New translations messages.xlf (Finnish)
[ci skip]

* New translations messages.xlf (Hebrew)
[ci skip]

* New translations messages.xlf (Italian)
[ci skip]

* New translations messages.xlf (Dutch)
[ci skip]

* New translations messages.xlf (Norwegian)
[ci skip]

* New translations messages.xlf (Polish)
[ci skip]

* New translations messages.xlf (Portuguese)
[ci skip]

* New translations messages.xlf (Russian)
[ci skip]

* New translations messages.xlf (Slovenian)
[ci skip]

* New translations messages.xlf (Swedish)
[ci skip]

* New translations messages.xlf (Turkish)
[ci skip]

* New translations messages.xlf (Chinese Simplified)
[ci skip]

* New translations messages.xlf (Portuguese, Brazilian)
[ci skip]

* New translations messages.xlf (Indonesian)
[ci skip]

* New translations messages.xlf (Croatian)
[ci skip]

* New translations messages.xlf (Luxembourgish)
[ci skip]

* New translations messages.xlf (Serbian (Latin))
[ci skip]

* New translations messages.xlf (Hungarian)
[ci skip]

* New translations messages.xlf (Romanian)
[ci skip]

* New translations messages.xlf (Afrikaans)
[ci skip]

* New translations messages.xlf (Slovak)
[ci skip]
2023-06-21 08:03:43 -07:00
Trenton H
1c66daf12b Ignore errors when trying to copy the original file's stats 2023-06-21 07:54:27 -07:00
shamoon
59d683849e Merge pull request #3645 from plu/test_3631
Add test for not moving default thumbnail
2023-06-20 16:43:16 -07:00
Johannes Plunien
9946acb1a0 Add test for not moving default thumbnail
See also #3632 and #3631
2023-06-20 20:54:15 +02:00
Johannes Plunien
83a760644d Copy default thumbnail if thumbnail generation fails
Fix #3631
2023-06-20 11:28:46 -07:00
shamoon
25ccff8640 Merge pull request #3641 from paperless-ngx/update-stale-labels
Chore: include 'not a bug' for stale action
2023-06-20 11:00:44 -07:00
Trenton H
5c4c5a7794 Explicitly set some environment for each supervised program, as it is not updated by supervisord 2023-06-20 10:53:33 -07:00
shamoon
cb6af97595 Include 'not a bug' for stale action 2023-06-20 10:53:05 -07:00
Trenton H
c4407dccf6 Updates the default Postgres to 15 for new installs 2023-06-20 10:35:48 -07:00
Trenton H
ecdea4c3c8 Updates the stale timing and close timing 2023-06-20 08:29:19 -07:00
Trenton H
26d6f302cf When starting with an external DB, start it for a bit first to allow its setup to complete 2023-06-20 08:20:44 -07:00
github-actions[bot]
ecf10622ef [Documentation] Add v1.16.2 changelog (#3629)
* Changelog v1.16.2 - GHA

* Update changelog.md

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2023-06-19 19:52:11 -07:00
Trenton H
0fb553675b Resets -dev version string 2023-06-19 09:39:50 -07:00
215 changed files with 34443 additions and 20982 deletions

View File

@@ -1,3 +1,17 @@
codecov:
require_ci_to_pass: true
# https://docs.codecov.com/docs/flags#recommended-automatic-flag-management
# Require each flag to have 1 upload before notification
flag_management:
default_rules:
after_n_builds: 1
individual_flags:
- name: backend
paths:
- src/
- name: frontend
paths:
- src-ui/
# https://docs.codecov.com/docs/pull-request-comments
# codecov will only comment if coverage changes
comment:

View File

@@ -20,11 +20,16 @@ NOTE: Please check only one box!
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Other (please explain)
- [ ] Other (please explain):
## Checklist:
<!--
NOTE: PRs that do not address the following will not be merged, please do not skip any relevant items.
-->
- [ ] I have read & agree with the [contributing guidelines](https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md).
- [ ] If applicable, I have included testing coverage for new code in this PR, for [backend](https://docs.paperless-ngx.com/development/#testing) and / or [front-end](https://docs.paperless-ngx.com/development/#testing-and-code-style) changes.
- [ ] If applicable, I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers.
- [ ] If applicable, I have checked that all tests pass, see [documentation](https://docs.paperless-ngx.com/development/#back-end-development).
- [ ] I have run all `pre-commit` hooks, see [documentation](https://docs.paperless-ngx.com/development/#code-formatting-with-pre-commit-hooks).

View File

@@ -17,6 +17,21 @@ updates:
# Add reviewers
reviewers:
- "paperless-ngx/frontend"
groups:
frontend-angular-dependencies:
patterns:
- "@angular*"
- "@ng-*"
- "ngx-*"
- "ng2-pdf-viewer"
frontend-jest-dependencies:
patterns:
- "@types/jest"
- "jest"
frontend-eslint-dependencies:
patterns:
- "@typescript-eslint*"
- "eslint"
# Enable version updates for Python
- package-ecosystem: "pip"

23
.github/stale.yml vendored
View File

@@ -1,23 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Only issues or pull requests with any of these labels are check if stale. Defaults to `[]` (disabled)
any-of-labels: ['cant-reproduce','not a bug','unconfirmed']
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# See https://github.com/marketplace/stale for more info on the app
# and https://github.com/probot/stale for the configuration docs

View File

@@ -16,7 +16,7 @@ on:
env:
# This is the version of pipenv all the steps will use
# If changing this, change Dockerfile
DEFAULT_PIP_ENV_VERSION: "2023.6.12"
DEFAULT_PIP_ENV_VERSION: "2023.7.23"
# This is the default version of Python to use in most steps
# If changing this, change Dockerfile
DEFAULT_PYTHON_VERSION: "3.9"
@@ -158,14 +158,14 @@ jobs:
cd src/
pipenv --python ${{ steps.setup-python.outputs.python-version }} run pytest -ra
-
name: Upload coverage to Codecov
name: Upload coverage
if: ${{ matrix.python-version == env.DEFAULT_PYTHON_VERSION }}
uses: codecov/codecov-action@v3
uses: actions/upload-artifact@v3
with:
# not required for public repos, but intermittently fails otherwise
token: ${{ secrets.CODECOV_TOKEN }}
# future expansion
flags: backend
name: backend-coverage-report
path: src/coverage.xml
retention-days: 7
if-no-files-found: warn
-
name: Stop containers
if: always()
@@ -210,15 +210,7 @@ jobs:
name: jest-coverage-report
path: src-ui/coverage
retention-days: 7
-
name: Upload frontend coverage to Codecov
if: always()
uses: codecov/codecov-action@v3
with:
# not required for public repos, but intermittently fails otherwise
token: ${{ secrets.CODECOV_TOKEN }}
# future expansion
flags: frontend
if-no-files-found: warn
-
name: Run Playwright e2e tests
run: cd src-ui && npx playwright test
@@ -231,6 +223,45 @@ jobs:
path: src-ui/playwright-report
retention-days: 7
tests-coverage-upload:
name: "Upload coverage"
runs-on: ubuntu-22.04
needs:
- tests-backend
- tests-frontend
steps:
-
uses: actions/checkout@v3
-
name: Download frontend coverage
uses: actions/download-artifact@v3
with:
name: jest-coverage-report
path: src-ui/
-
name: Upload frontend coverage to Codecov
uses: codecov/codecov-action@v3
with:
# not required for public repos, but intermittently fails otherwise
token: ${{ secrets.CODECOV_TOKEN }}
flags: frontend
directory: src-ui/
-
name: Download backend coverage
uses: actions/download-artifact@v3
with:
name: backend-coverage-report
path: src/
-
name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
# not required for public repos, but intermittently fails otherwise
token: ${{ secrets.CODECOV_TOKEN }}
# future expansion
flags: backend
directory: src/
build-docker-image:
name: Build Docker image for ${{ github.ref_name }}
runs-on: ubuntu-22.04

View File

@@ -29,7 +29,7 @@ jobs:
-
name: Clean temporary images
if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/ephemeral@v0.1.0
uses: stumpylog/image-cleaner-action/ephemeral@v0.2.0
with:
token: "${{ env.TOKEN }}"
owner: "${{ github.repository_owner }}"
@@ -68,7 +68,7 @@ jobs:
-
name: Clean untagged images
if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/untagged@v0.1.0
uses: stumpylog/image-cleaner-action/untagged@v0.2.0
with:
token: "${{ env.TOKEN }}"
owner: "${{ github.repository_owner }}"

View File

@@ -19,9 +19,9 @@ jobs:
steps:
- uses: actions/stale@v8
with:
days-before-stale: 30
days-before-close: 7
only-labels: 'cant-reproduce'
days-before-stale: 7
days-before-close: 14
any-of-labels: 'cant-reproduce,not a bug'
stale-issue-label: stale
stale-pr-label: stale
stale-issue-message: >

View File

@@ -27,7 +27,7 @@ repos:
- id: check-case-conflict
- id: detect-private-key
- repo: https://github.com/pre-commit/mirrors-prettier
rev: 'v2.7.1'
rev: 'v3.0.0'
hooks:
- id: prettier
types_or:
@@ -37,11 +37,11 @@ repos:
exclude: "(^Pipfile\\.lock$)"
# Python hooks
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.0.272'
rev: 'v0.0.280'
hooks:
- id: ruff
- repo: https://github.com/psf/black
rev: 23.3.0
rev: 23.7.0
hooks:
- id: black
# Dockerfile hooks

View File

@@ -2,3 +2,5 @@
semi: false
# https://prettier.io/docs/en/options.html#quotes
singleQuote: true
# https://prettier.io/docs/en/options.html#trailing-commas
trailingComma: "es5"

View File

@@ -2,7 +2,7 @@
# https://beta.ruff.rs/docs/rules/
extend-select = ["I", "W", "UP", "COM", "DJ", "EXE", "ISC", "ICN", "G201", "INP", "PIE", "RSE", "SIM", "TID", "PLC", "PLE", "RUF"]
# TODO PTH
ignore = ["DJ001", "SIM105"]
ignore = ["DJ001", "SIM105", "RUF012"]
fix = true
line-length = 88
respect-gitignore = true

View File

@@ -45,7 +45,7 @@ Examples of `non-trivial` PRs might include:
- Additional features
- Large changes to many distinct files
- Breaking or depreciation of existing features
- Breaking or deprecation of existing features
Our community review process for `non-trivial` PRs is the following:

View File

@@ -29,7 +29,7 @@ COPY Pipfile* ./
RUN set -eux \
&& echo "Installing pipenv" \
&& python3 -m pip install --no-cache-dir --upgrade pipenv==2023.6.12 \
&& python3 -m pip install --no-cache-dir --upgrade pipenv==2023.7.23 \
&& echo "Generating requirement.txt" \
&& pipenv requirements > requirements.txt
@@ -214,7 +214,8 @@ COPY --from=pipenv-base /usr/src/pipenv/requirements.txt ./
ARG BUILD_PACKAGES="\
build-essential \
git \
default-libmysqlclient-dev"
default-libmysqlclient-dev \
pkg-config"
# hadolint ignore=DL3042
RUN --mount=type=cache,target=/root/.cache/pip/,id=pip-cache \

15
Pipfile
View File

@@ -18,7 +18,7 @@ django-celery-results = "*"
django-compression-middleware = "*"
django-guardian = "*"
django-extensions = "*"
django-filter = "~=22.1"
django-filter = "~=23.1"
djangorestframework = "~=3.14"
djangorestframework-guardian = "*"
filelock = "*"
@@ -26,8 +26,6 @@ gunicorn = "*"
imap-tools = "*"
langdetect = "*"
pathvalidate = "*"
pillow = "*"
pikepdf = "*"
python-gnupg = "*"
python-dotenv = "*"
python-dateutil = "*"
@@ -36,9 +34,9 @@ python-ipware = "*"
psycopg2 = "*"
rapidfuzz = "*"
redis = {extras = ["hiredis"], version = "*"}
scikit-learn = "~=1.2"
whitenoise = "~=6.3"
watchdog = "~=2.2"
scikit-learn = "~=1.3"
whitenoise = "~=6.5"
watchdog = "~=3.0"
whoosh="~=2.7"
inotifyrecursive = "~=0.3"
ocrmypdf = "~=14.0"
@@ -64,8 +62,10 @@ zxing-cpp = {version = "*", platform_machine = "== 'x86_64'"}
scipy = "==1.8.1"
# v4 brings in extra dependencies for features not used here
reportlab = "==3.6.12"
# Pin this until piwheels is building a newer version (see https://www.piwheels.org/project/cryptography/)
# Pin these until piwheels is building a newer version (see https://www.piwheels.org/project/{package}/)
cryptography = "==40.0.1"
pikepdf = "==7.2.0"
pillow = "==9.5.0"
[dev-packages]
# Linting
@@ -81,6 +81,7 @@ pytest-httpx = "*"
pytest-env = "*"
pytest-sugar = "*"
pytest-xdist = "*"
pytest-rerunfailures = "*"
"pdfminer.six" = "*"
imagehash = "*"
daphne = "*"

1972
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@ services:
- redisdata:/data
db:
image: docker.io/library/postgres:13
image: docker.io/library/postgres:15
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data

View File

@@ -39,7 +39,7 @@ services:
- redisdata:/data
db:
image: docker.io/library/postgres:13
image: docker.io/library/postgres:15
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data

View File

@@ -35,7 +35,7 @@ services:
- redisdata:/data
db:
image: docker.io/library/postgres:13
image: docker.io/library/postgres:15
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data

View File

@@ -15,6 +15,7 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment = HOME="/usr/src/paperless",USER="paperless"
[program:consumer]
command=python3 manage.py document_consumer
@@ -25,6 +26,7 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment = HOME="/usr/src/paperless",USER="paperless"
[program:celery]
@@ -37,6 +39,7 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment = HOME="/usr/src/paperless",USER="paperless"
[program:celery-beat]
@@ -48,6 +51,7 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment = HOME="/usr/src/paperless",USER="paperless"
[program:celery-flower]
command = /usr/local/bin/flower-conditional.sh
@@ -58,3 +62,4 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment = HOME="/usr/src/paperless",USER="paperless"

View File

@@ -68,23 +68,23 @@ $ docker-compose down
After that, [make a backup](#backup).
1. If you pull the image from the docker hub, all you need to do is:
1. If you pull the image from the docker hub, all you need to do is:
```shell-session
$ docker-compose pull
$ docker-compose up
```
```shell-session
$ docker-compose pull
$ docker-compose up
```
The docker-compose files refer to the `latest` version, which is
always the latest stable release.
The docker-compose files refer to the `latest` version, which is
always the latest stable release.
2. If you built the image yourself, do the following:
1. If you built the image yourself, do the following:
```shell-session
$ git pull
$ docker-compose build
$ docker-compose up
```
```shell-session
$ git pull
$ docker-compose build
$ docker-compose up
```
Running `docker-compose up` will also apply any new database migrations.
If you see everything working, press CTRL+C once to gracefully stop
@@ -167,6 +167,16 @@ following:
This might not actually do anything. Not every new paperless version
comes with new database migrations.
### Database Upgrades
In general, paperless does not require a specific version of PostgreSQL or MariaDB and it is
safe to update them to newer versions. However, you should always take a backup and follow
the instructions from your database's documentation for how to upgrade between major versions.
For PostgreSQL, refer to [Upgrading a PostgreSQL Cluster](https://www.postgresql.org/docs/current/upgrading.html).
For MariaDB, refer to [Upgrading MariaDB](https://mariadb.com/kb/en/upgrading/)
## Downgrading Paperless {#downgrade-paperless}
Downgrades are possible. However, some updates also contain database
@@ -460,7 +470,7 @@ The issues detected by the sanity checker are as follows:
- Inaccessible thumbnails due to improper permissions.
- Documents without any content (warning).
- Orphaned files in the media directory (warning). These are files
that are not referenced by any document im paperless.
that are not referenced by any document in paperless.
```
document_sanity_checker

View File

@@ -1,6 +1,6 @@
# Advanced Topics
Paperless offers a couple features that automate certain tasks and make
Paperless offers a couple of features that automate certain tasks and make
your life easier.
## Matching tags, correspondents, document types, and storage paths {#matching}
@@ -35,9 +35,9 @@ The following algorithms are available:
(i.e. preserve ordering) in the PDF.
- **Regular expression:** Parses the match as a regular expression and
tries to find a match within the document.
- **Fuzzy match:** I don't know. Look at the source.
- **Fuzzy match:** I don't know. Look at [the source](https://github.com/paperless-ngx/paperless-ngx/blob/main/src/documents/matching.py).
- **Auto:** Tries to automatically match new documents. This does not
require you to set a match. See the notes below.
require you to set a match. See the [notes below](#automatic-matching).
When using the _any_ or _all_ matching algorithms, you can search for
terms that consist of multiple words by enclosing them in double quotes.
@@ -92,7 +92,7 @@ when using this feature:
decide when not to assign a certain tag, correspondent, document
type, or storage path. This will usually be the case as you start
filling up paperless with documents. Example: If all your documents
are either from "Webshop" and "Bank", paperless will assign one
are either from "Webshop" or "Bank", paperless will assign one
of these correspondents to ANY new document, if both are set to
automatic matching.
@@ -101,7 +101,7 @@ when using this feature:
Sometimes you may want to do something arbitrary whenever a document is
consumed. Rather than try to predict what you may want to do, Paperless
lets you execute scripts of your own choosing just before or after a
document is consumed using a couple simple hooks.
document is consumed using a couple of simple hooks.
Just write a script, put it somewhere that Paperless can read & execute,
and then put the path to that script in `paperless.conf` or
@@ -197,7 +197,7 @@ The script can be in any language, A simple shell script example:
!!! warning
The post consumption script should not modify the document files
directly
directly.
The script's stdout and stderr will be logged line by line to the
webserver log, along with the exit code of the script.
@@ -311,6 +311,7 @@ Paperless provides the following placeholders within filenames:
- `{added_day}`: Day added only (number 01-31).
- `{owner_username}`: Username of document owner, if any, or "none"
- `{original_name}`: Document original filename, minus the extension, if any, or "none"
- `{doc_pk}`: The paperless identifier (primary key) for the document.
Paperless will try to conserve the information from your database as
much as possible. However, some characters that you can use in document
@@ -528,7 +529,7 @@ For how to enable barcode usage, see [the configuration](/configuration#barcodes
The two settings may be enabled independently, but do have interactions as explained
below.
### Document Splitting
### Document Splitting {#document-splitting}
When enabled, Paperless will look for a barcode with the configured value and create a new document
starting from the next page. The page with the barcode on it will _not_ be retained. It
@@ -543,3 +544,75 @@ If document splitting via barcode is also enabled, documents will be split when
barcode is located. However, differing from the splitting, the page with the
barcode _will_ be retained. This allows application of a barcode to any page, including
one which holds data to keep in the document.
## Automatic collation of double-sided documents {#collate}
!!! note
If your scanner supports double-sided scanning natively, you do not need this feature.
This feature is turned off by default, see [configuration](/configuration#collate) on how to turn it on.
### Summary
If you have a scanner with an automatic document feeder (ADF) that only scans a single side,
this feature makes scanning double-sided documents much more convenient by automatically
collating two separate scans into one document, reordering the pages as necessary.
### Usage example
Suppose you have a double-sided document with 6 pages (3 sheets of paper). First,
put the stack into your ADF as normal, ensuring that page 1 is scanned first. Your ADF
will now scan pages 1, 3, and 5. Then you (or your the scanner, if it supports it) upload
the scan into the correct sub-directory of the consume folder (`double-sided` by default;
keep in mind that Paperless will _not_ automatically create the directory for you.)
Paperless will then process the scan and move it into an internal staging area.
The next step is to turn your stack upside down (without reordering the sheets of paper),
and scan it once again, your ADF will now scan pages 6, 4, and 2, in that order. Once this
scan is copied into the sub-directory, Paperless will collate the previous scan with the
new one, reversing the order of the pages on the second, "even numbered" scan. The
resulting document will have the pages 1-6 in the correct order, and this new file will
then be processed as normal.
!!! tip
When scanning the even numbered pages, you can omit the last empty pages, if there are
any. For example, if page 6 is empty, you only need to scan pages 2 and 4. _Do not_ omit
empty pages in the middle of the document.
### Things that could go wrong
Paperless will notice when the first, "odd numbered" scan has less pages than the second
scan (this can happen when e.g. the ADF skipped a few pages in the first pass). In that
case, Paperless will remove the staging copy as well as the scan, and give you an error
message asking you to restart the process from scratch, by scanning the odd pages again,
followed by the even pages.
It's important that the scan files get consumed in the correct order, and one at a time.
You therefore need to make sure that Paperless is running while you upload the files into
the directory; and if you're using [polling](/configuration#polling), make sure that
`CONSUMER_POLLING` is set to a value lower than it takes for the second scan to appear,
like 5-10 or even lower.
Another thing that might happen is that you start a double sided scan, but then forget
to upload the second file. To avoid collating the wrong documents if you then come back
a day later to scan a new double-sided document, Paperless will only keep an "odd numbered
pages" file for up to 30 minutes. If more time passes, it will consider the next incoming
scan a completely new "odd numbered pages" one. The old staging file will get discarded.
### Interaction with "subdirs as tags"
The collation feature can be used together with the [subdirs as tags](/configuration#consume_config)
feature (but this is not a requirement). Just create a correctly named double-sided subdir
in the hierachy and upload your scans there. For example, both `double-sided/foo/bar` as
well as `foo/bar/double-sided` will cause the collated document to be treated as if it
were uploaded into `foo/bar` and receive both `foo` and `bar` tags, but not `double-sided`.
### Interaction with document splitting
You can use the [document splitting](#document-splitting) feature, but if you use a normal
single-sided split marker page, the split document(s) will have an empty page at the front (or
whatever else was on the backside of the split marker page.) You can work around that by having
a split marker page that has the split barcode on _both_ sides. This way, the extra page will
get automatically removed.

View File

@@ -288,10 +288,23 @@ with an optional `set_permissions` parameter which is of the form:
}
```
!!! note
Arrays should contain user or group ID numbers.
If this parameter is supplied the object's permissions will be overwritten,
assuming the authenticated user has permission to do so (the user must be
the object owner or a superuser).
### Retrieving full permissions
By default, the API will return a truncated version of object-level
permissions, returning `user_can_change` indicating whether the current user
can edit the object (either because they are the object owner or have permissions
granted). You can pass the parameter `full_perms=true` to API calls to view the
full permissions of objects in a format that mirrors the `set_permissions`
parameter above.
## API Versioning
The REST API is versioned since Paperless-ngx 1.3.0.

View File

@@ -1,5 +1,290 @@
# Changelog
## paperless-ngx 1.17.3
### Bug Fixes
- Fix: When PDF/A rendering fails, add a consideration for the user to add args to override [@stumpylog](https://github.com/stumpylog) ([#4083](https://github.com/paperless-ngx/paperless-ngx/pull/4083))
### Dependencies
- Chore: update frontend PDF viewer (including pdf-js) [@shamoon](https://github.com/shamoon) ([#4065](https://github.com/paperless-ngx/paperless-ngx/pull/4065))
### Maintenance
- Dev: Upload code coverage in the same job [@stumpylog](https://github.com/stumpylog) ([#4084](https://github.com/paperless-ngx/paperless-ngx/pull/4084))
### All App Changes
<details>
<summary>3 changes</summary>
- Fix: When PDF/A rendering fails, add a consideration for the user to add args to override [@stumpylog](https://github.com/stumpylog) ([#4083](https://github.com/paperless-ngx/paperless-ngx/pull/4083))
- Chore: update frontend PDF viewer (including pdf-js) [@shamoon](https://github.com/shamoon) ([#4065](https://github.com/paperless-ngx/paperless-ngx/pull/4065))
- Chore: Prepare for Python 3.11 support [@stumpylog](https://github.com/stumpylog) ([#4066](https://github.com/paperless-ngx/paperless-ngx/pull/4066))
</details>
## paperless-ngx 1.17.2
### Features
- Enhancement: Allow to set a prefix for keys and channels in redis [@amo13](https://github.com/amo13) ([#3993](https://github.com/paperless-ngx/paperless-ngx/pull/3993))
### Bug Fixes
- Fix: Increase the HTTP timeouts for Tika/Gotenberg to maximum task time [@stumpylog](https://github.com/stumpylog) ([#4061](https://github.com/paperless-ngx/paperless-ngx/pull/4061))
- Fix: Allow adding an SSL certificate for IMAP SSL context [@stumpylog](https://github.com/stumpylog) ([#4048](https://github.com/paperless-ngx/paperless-ngx/pull/4048))
- Fix: tag creation sometimes retained search text [@shamoon](https://github.com/shamoon) ([#4038](https://github.com/paperless-ngx/paperless-ngx/pull/4038))
- Fix: enforce permissions on bulk_edit operations [@shamoon](https://github.com/shamoon) ([#4007](https://github.com/paperless-ngx/paperless-ngx/pull/4007))
### All App Changes
<details>
<summary>6 changes</summary>
- Fix: Increase the HTTP timeouts for Tika/Gotenberg to maximum task time [@stumpylog](https://github.com/stumpylog) ([#4061](https://github.com/paperless-ngx/paperless-ngx/pull/4061))
- Enhancement: disable / hide some UI buttons / elements if insufficient permissions, show errors [@shamoon](https://github.com/shamoon) ([#4014](https://github.com/paperless-ngx/paperless-ngx/pull/4014))
- Fix: Allow adding an SSL certificate for IMAP SSL context [@stumpylog](https://github.com/stumpylog) ([#4048](https://github.com/paperless-ngx/paperless-ngx/pull/4048))
- Fix: tag creation sometimes retained search text [@shamoon](https://github.com/shamoon) ([#4038](https://github.com/paperless-ngx/paperless-ngx/pull/4038))
- Fix: enforce permissions on bulk_edit operations [@shamoon](https://github.com/shamoon) ([#4007](https://github.com/paperless-ngx/paperless-ngx/pull/4007))
- Enhancement: Allow to set a prefix for keys and channels in redis [@amo13](https://github.com/amo13) ([#3993](https://github.com/paperless-ngx/paperless-ngx/pull/3993))
</details>
## paperless-ngx 1.17.1
### Features
- Fix / Enhancement: restrict status messages by owner if set \& improve 404 page [@shamoon](https://github.com/shamoon) ([#3959](https://github.com/paperless-ngx/paperless-ngx/pull/3959))
- Feature: Add Ukrainian translation [@shamoon](https://github.com/shamoon) ([#3941](https://github.com/paperless-ngx/paperless-ngx/pull/3941))
### Bug Fixes
- Fix: handle ASN = 0 on frontend cards [@shamoon](https://github.com/shamoon) ([#3988](https://github.com/paperless-ngx/paperless-ngx/pull/3988))
- Fix: improve light color filled primary button text legibility [@shamoon](https://github.com/shamoon) ([#3980](https://github.com/paperless-ngx/paperless-ngx/pull/3980))
- Fix / Enhancement: restrict status messages by owner if set \& improve 404 page [@shamoon](https://github.com/shamoon) ([#3959](https://github.com/paperless-ngx/paperless-ngx/pull/3959))
- Fix: handle very old date strings in correspondent list [@shamoon](https://github.com/shamoon) ([#3953](https://github.com/paperless-ngx/paperless-ngx/pull/3953))
### Documentation
- docs(bare-metal): add new dependency [@bin101](https://github.com/bin101) ([#3931](https://github.com/paperless-ngx/paperless-ngx/pull/3931))
### Dependencies
- Chore: Loosen Pipfile restriction on some packages and update them [@stumpylog](https://github.com/stumpylog) ([#3972](https://github.com/paperless-ngx/paperless-ngx/pull/3972))
### All App Changes
<details>
<summary>6 changes</summary>
- Fix: handle ASN = 0 on frontend cards [@shamoon](https://github.com/shamoon) ([#3988](https://github.com/paperless-ngx/paperless-ngx/pull/3988))
- Fix: improve light color filled primary button text legibility [@shamoon](https://github.com/shamoon) ([#3980](https://github.com/paperless-ngx/paperless-ngx/pull/3980))
- Fix / Enhancement: restrict status messages by owner if set \& improve 404 page [@shamoon](https://github.com/shamoon) ([#3959](https://github.com/paperless-ngx/paperless-ngx/pull/3959))
- Fix: handle very old date strings in correspondent list [@shamoon](https://github.com/shamoon) ([#3953](https://github.com/paperless-ngx/paperless-ngx/pull/3953))
- Chore: Reduces the 2 mail tests flakiness [@stumpylog](https://github.com/stumpylog) ([#3949](https://github.com/paperless-ngx/paperless-ngx/pull/3949))
- Feature: Add Ukrainian translation [@shamoon](https://github.com/shamoon) ([#3941](https://github.com/paperless-ngx/paperless-ngx/pull/3941))
</details>
## paperless-ngx 1.17.0
### Features
- Add support for additional UK date formats [@brainrecursion](https://github.com/brainrecursion) ([#3887](https://github.com/paperless-ngx/paperless-ngx/pull/3887))
- Add 'doc_pk' to PAPERLESS_FILENAME_FORMAT handling [@mechanarchy](https://github.com/mechanarchy) ([#3861](https://github.com/paperless-ngx/paperless-ngx/pull/3861))
- Feature: hover buttons for saved view widgets [@shamoon](https://github.com/shamoon) ([#3875](https://github.com/paperless-ngx/paperless-ngx/pull/3875))
- Feature: collate two single-sided multipage scans [@brakhane](https://github.com/brakhane) ([#3784](https://github.com/paperless-ngx/paperless-ngx/pull/3784))
- Feature: include global and object-level permissions in export / import [@shamoon](https://github.com/shamoon) ([#3672](https://github.com/paperless-ngx/paperless-ngx/pull/3672))
- Enhancement / Fix: Migrate encrypted png thumbnails to webp [@shamoon](https://github.com/shamoon) ([#3719](https://github.com/paperless-ngx/paperless-ngx/pull/3719))
- Feature: Add Slovak translation [@shamoon](https://github.com/shamoon) ([#3722](https://github.com/paperless-ngx/paperless-ngx/pull/3722))
### Bug Fixes
- Fix: cancel possibly slow queries on doc details [@shamoon](https://github.com/shamoon) ([#3925](https://github.com/paperless-ngx/paperless-ngx/pull/3925))
- Fix: note creation / deletion should respect doc permissions [@shamoon](https://github.com/shamoon) ([#3903](https://github.com/paperless-ngx/paperless-ngx/pull/3903))
- Fix: notes show persistent scrollbars [@shamoon](https://github.com/shamoon) ([#3904](https://github.com/paperless-ngx/paperless-ngx/pull/3904))
- Fix: Provide SSL context to IMAP client [@stumpylog](https://github.com/stumpylog) ([#3886](https://github.com/paperless-ngx/paperless-ngx/pull/3886))
- Fix/enhancement: permissions for mail rules \& accounts [@shamoon](https://github.com/shamoon) ([#3869](https://github.com/paperless-ngx/paperless-ngx/pull/3869))
- Fix: Classifier special case when no items are set to automatic matching [@stumpylog](https://github.com/stumpylog) ([#3858](https://github.com/paperless-ngx/paperless-ngx/pull/3858))
- Fix: issues with copy2 or copystat and SELinux permissions [@stumpylog](https://github.com/stumpylog) ([#3847](https://github.com/paperless-ngx/paperless-ngx/pull/3847))
- Fix: Parsing office document timestamps [@stumpylog](https://github.com/stumpylog) ([#3836](https://github.com/paperless-ngx/paperless-ngx/pull/3836))
- Fix: Add warning to install script need for permissions [@shamoon](https://github.com/shamoon) ([#3835](https://github.com/paperless-ngx/paperless-ngx/pull/3835))
- Fix interaction between API and barcode archive serial number [@stumpylog](https://github.com/stumpylog) ([#3834](https://github.com/paperless-ngx/paperless-ngx/pull/3834))
- Enhancement / Fix: Migrate encrypted png thumbnails to webp [@shamoon](https://github.com/shamoon) ([#3719](https://github.com/paperless-ngx/paperless-ngx/pull/3719))
- Fix: add UI tour step padding [@hakimio](https://github.com/hakimio) ([#3791](https://github.com/paperless-ngx/paperless-ngx/pull/3791))
- Fix: translate file tasks types in footer [@shamoon](https://github.com/shamoon) ([#3749](https://github.com/paperless-ngx/paperless-ngx/pull/3749))
- Fix: limit ng-select size for addition of filter button [@shamoon](https://github.com/shamoon) ([#3731](https://github.com/paperless-ngx/paperless-ngx/pull/3731))
### Documentation
- Documentation: improvements to grammar, spelling, indentation [@mechanarchy](https://github.com/mechanarchy) ([#3844](https://github.com/paperless-ngx/paperless-ngx/pull/3844))
### Maintenance
- Bump stumpylog/image-cleaner-action from 0.1.0 to 0.2.0 [@dependabot](https://github.com/dependabot) ([#3910](https://github.com/paperless-ngx/paperless-ngx/pull/3910))
- Chore: group frontend angular dependabot updates [@shamoon](https://github.com/shamoon) ([#3750](https://github.com/paperless-ngx/paperless-ngx/pull/3750))
### Dependencies
<details>
<summary>17 changes</summary>
- Chore: Bump the frontend-angular-dependencies group in /src-ui with 11 updates [@shamoon](https://github.com/shamoon) ([#3918](https://github.com/paperless-ngx/paperless-ngx/pull/3918))
- Bump stumpylog/image-cleaner-action from 0.1.0 to 0.2.0 [@dependabot](https://github.com/dependabot) ([#3910](https://github.com/paperless-ngx/paperless-ngx/pull/3910))
- Bump the frontend-eslint-dependencies group in /src-ui with 3 updates [@dependabot](https://github.com/dependabot) ([#3911](https://github.com/paperless-ngx/paperless-ngx/pull/3911))
- Bump tslib from 2.6.0 to 2.6.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#3909](https://github.com/paperless-ngx/paperless-ngx/pull/3909))
- Bump jest-environment-jsdom from 29.5.0 to 29.6.2 in /src-ui [@dependabot](https://github.com/dependabot) ([#3916](https://github.com/paperless-ngx/paperless-ngx/pull/3916))
- Bump [@<!---->types/node from 20.3.3 to 20.4.5 in /src-ui @dependabot](https://github.com/<!---->types/node from 20.3.3 to 20.4.5 in /src-ui @dependabot) ([#3915](https://github.com/paperless-ngx/paperless-ngx/pull/3915))
- Bump bootstrap from 5.3.0 to 5.3.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#3914](https://github.com/paperless-ngx/paperless-ngx/pull/3914))
- Bump [@<!---->playwright/test from 1.36.1 to 1.36.2 in /src-ui @dependabot](https://github.com/<!---->playwright/test from 1.36.1 to 1.36.2 in /src-ui @dependabot) ([#3912](https://github.com/paperless-ngx/paperless-ngx/pull/3912))
- Bump the frontend-jest-dependencies group in /src-ui with 1 update [@dependabot](https://github.com/dependabot) ([#3906](https://github.com/paperless-ngx/paperless-ngx/pull/3906))
- Chore: Update dependencies [@stumpylog](https://github.com/stumpylog) ([#3883](https://github.com/paperless-ngx/paperless-ngx/pull/3883))
- Chore: Update Python dependencies [@stumpylog](https://github.com/stumpylog) ([#3842](https://github.com/paperless-ngx/paperless-ngx/pull/3842))
- Bump the frontend-angular-dependencies group in /src-ui with 16 updates [@dependabot](https://github.com/dependabot) ([#3826](https://github.com/paperless-ngx/paperless-ngx/pull/3826))
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.60.1 to 6.1.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.60.1 to 6.1.0 in /src-ui @dependabot) ([#3829](https://github.com/paperless-ngx/paperless-ngx/pull/3829))
- Bump jest and [@<!---->types/jest in /src-ui @dependabot](https://github.com/<!---->types/jest in /src-ui @dependabot) ([#3828](https://github.com/paperless-ngx/paperless-ngx/pull/3828))
- Bump [@<!---->playwright/test from 1.36.0 to 1.36.1 in /src-ui @dependabot](https://github.com/<!---->playwright/test from 1.36.0 to 1.36.1 in /src-ui @dependabot) ([#3827](https://github.com/paperless-ngx/paperless-ngx/pull/3827))
- Bump semver from 5.7.1 to 5.7.2 in /src-ui [@dependabot](https://github.com/dependabot) ([#3793](https://github.com/paperless-ngx/paperless-ngx/pull/3793))
- Chore: Bump Angular to v16 and other frontend packages [@dependabot](https://github.com/dependabot) ([#3727](https://github.com/paperless-ngx/paperless-ngx/pull/3727))
</details>
### All App Changes
<details>
<summary>35 changes</summary>
- Fix: cancel possibly slow queries on doc details [@shamoon](https://github.com/shamoon) ([#3925](https://github.com/paperless-ngx/paperless-ngx/pull/3925))
- [BUG] Set office document creation date with timezone, if it is naive [@a17t](https://github.com/a17t) ([#3760](https://github.com/paperless-ngx/paperless-ngx/pull/3760))
- Fix: note creation / deletion should respect doc permissions [@shamoon](https://github.com/shamoon) ([#3903](https://github.com/paperless-ngx/paperless-ngx/pull/3903))
- Chore: Bump the frontend-angular-dependencies group in /src-ui with 11 updates [@shamoon](https://github.com/shamoon) ([#3918](https://github.com/paperless-ngx/paperless-ngx/pull/3918))
- Bump the frontend-eslint-dependencies group in /src-ui with 3 updates [@dependabot](https://github.com/dependabot) ([#3911](https://github.com/paperless-ngx/paperless-ngx/pull/3911))
- Bump tslib from 2.6.0 to 2.6.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#3909](https://github.com/paperless-ngx/paperless-ngx/pull/3909))
- Bump jest-environment-jsdom from 29.5.0 to 29.6.2 in /src-ui [@dependabot](https://github.com/dependabot) ([#3916](https://github.com/paperless-ngx/paperless-ngx/pull/3916))
- Bump [@<!---->types/node from 20.3.3 to 20.4.5 in /src-ui @dependabot](https://github.com/<!---->types/node from 20.3.3 to 20.4.5 in /src-ui @dependabot) ([#3915](https://github.com/paperless-ngx/paperless-ngx/pull/3915))
- Bump bootstrap from 5.3.0 to 5.3.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#3914](https://github.com/paperless-ngx/paperless-ngx/pull/3914))
- Bump [@<!---->playwright/test from 1.36.1 to 1.36.2 in /src-ui @dependabot](https://github.com/<!---->playwright/test from 1.36.1 to 1.36.2 in /src-ui @dependabot) ([#3912](https://github.com/paperless-ngx/paperless-ngx/pull/3912))
- Bump the frontend-jest-dependencies group in /src-ui with 1 update [@dependabot](https://github.com/dependabot) ([#3906](https://github.com/paperless-ngx/paperless-ngx/pull/3906))
- Fix: notes show persistent scrollbars [@shamoon](https://github.com/shamoon) ([#3904](https://github.com/paperless-ngx/paperless-ngx/pull/3904))
- Add support for additional UK date formats [@brainrecursion](https://github.com/brainrecursion) ([#3887](https://github.com/paperless-ngx/paperless-ngx/pull/3887))
- Add 'doc_pk' to PAPERLESS_FILENAME_FORMAT handling [@mechanarchy](https://github.com/mechanarchy) ([#3861](https://github.com/paperless-ngx/paperless-ngx/pull/3861))
- Fix: Provide SSL context to IMAP client [@stumpylog](https://github.com/stumpylog) ([#3886](https://github.com/paperless-ngx/paperless-ngx/pull/3886))
- Feature: hover buttons for saved view widgets [@shamoon](https://github.com/shamoon) ([#3875](https://github.com/paperless-ngx/paperless-ngx/pull/3875))
- Fix/enhancement: permissions for mail rules \& accounts [@shamoon](https://github.com/shamoon) ([#3869](https://github.com/paperless-ngx/paperless-ngx/pull/3869))
- Chore: typing improvements [@stumpylog](https://github.com/stumpylog) ([#3860](https://github.com/paperless-ngx/paperless-ngx/pull/3860))
- Fix: Classifier special case when no items are set to automatic matching [@stumpylog](https://github.com/stumpylog) ([#3858](https://github.com/paperless-ngx/paperless-ngx/pull/3858))
- Fix: issues with copy2 or copystat and SELinux permissions [@stumpylog](https://github.com/stumpylog) ([#3847](https://github.com/paperless-ngx/paperless-ngx/pull/3847))
- Chore: Update Python dependencies [@stumpylog](https://github.com/stumpylog) ([#3842](https://github.com/paperless-ngx/paperless-ngx/pull/3842))
- Feature: include global and object-level permissions in export / import [@shamoon](https://github.com/shamoon) ([#3672](https://github.com/paperless-ngx/paperless-ngx/pull/3672))
- Fix: Parsing office document timestamps [@stumpylog](https://github.com/stumpylog) ([#3836](https://github.com/paperless-ngx/paperless-ngx/pull/3836))
- Fix interaction between API and barcode archive serial number [@stumpylog](https://github.com/stumpylog) ([#3834](https://github.com/paperless-ngx/paperless-ngx/pull/3834))
- Bump the frontend-angular-dependencies group in /src-ui with 16 updates [@dependabot](https://github.com/dependabot) ([#3826](https://github.com/paperless-ngx/paperless-ngx/pull/3826))
- Enhancement / Fix: Migrate encrypted png thumbnails to webp [@shamoon](https://github.com/shamoon) ([#3719](https://github.com/paperless-ngx/paperless-ngx/pull/3719))
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.60.1 to 6.1.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.60.1 to 6.1.0 in /src-ui @dependabot) ([#3829](https://github.com/paperless-ngx/paperless-ngx/pull/3829))
- Bump jest and [@<!---->types/jest in /src-ui @dependabot](https://github.com/<!---->types/jest in /src-ui @dependabot) ([#3828](https://github.com/paperless-ngx/paperless-ngx/pull/3828))
- Bump [@<!---->playwright/test from 1.36.0 to 1.36.1 in /src-ui @dependabot](https://github.com/<!---->playwright/test from 1.36.0 to 1.36.1 in /src-ui @dependabot) ([#3827](https://github.com/paperless-ngx/paperless-ngx/pull/3827))
- Bump semver from 5.7.1 to 5.7.2 in /src-ui [@dependabot](https://github.com/dependabot) ([#3793](https://github.com/paperless-ngx/paperless-ngx/pull/3793))
- Fix: add UI tour step padding [@hakimio](https://github.com/hakimio) ([#3791](https://github.com/paperless-ngx/paperless-ngx/pull/3791))
- Fix: translate file tasks types in footer [@shamoon](https://github.com/shamoon) ([#3749](https://github.com/paperless-ngx/paperless-ngx/pull/3749))
- Feature: Add Slovak translation [@shamoon](https://github.com/shamoon) ([#3722](https://github.com/paperless-ngx/paperless-ngx/pull/3722))
- Fix: limit ng-select size for addition of filter button [@shamoon](https://github.com/shamoon) ([#3731](https://github.com/paperless-ngx/paperless-ngx/pull/3731))
- Chore: Bump Angular to v16 and other frontend packages [@dependabot](https://github.com/dependabot) ([#3727](https://github.com/paperless-ngx/paperless-ngx/pull/3727))
</details>
## paperless-ngx 1.16.5
### Features
- Feature: support barcode upscaling for better detection of small barcodes [@bmachek](https://github.com/bmachek) ([#3655](https://github.com/paperless-ngx/paperless-ngx/pull/3655))
### Bug Fixes
- Fix: owner removed when set_permissions passed on object create [@shamoon](https://github.com/shamoon) ([#3702](https://github.com/paperless-ngx/paperless-ngx/pull/3702))
### All App Changes
<details>
<summary>2 changes</summary>
- Feature: support barcode upscaling for better detection of small barcodes [@bmachek](https://github.com/bmachek) ([#3655](https://github.com/paperless-ngx/paperless-ngx/pull/3655))
- Fix: owner removed when set_permissions passed on object create [@shamoon](https://github.com/shamoon) ([#3702](https://github.com/paperless-ngx/paperless-ngx/pull/3702))
</details>
## paperless-ngx 1.16.4
### Bug Fixes
- Fix: prevent button wrapping when sidebar narrows in MS Edge [@shamoon](https://github.com/shamoon) ([#3682](https://github.com/paperless-ngx/paperless-ngx/pull/3682))
- Fix: Handling for filenames with non-ascii and no content attribute [@stumpylog](https://github.com/stumpylog) ([#3695](https://github.com/paperless-ngx/paperless-ngx/pull/3695))
- Fix: Generation of thumbnails for existing stored emails [@stumpylog](https://github.com/stumpylog) ([#3696](https://github.com/paperless-ngx/paperless-ngx/pull/3696))
- Fix: Use row gap for filter editor [@kleinweby](https://github.com/kleinweby) ([#3662](https://github.com/paperless-ngx/paperless-ngx/pull/3662))
### Documentation
- Documentation: update API docs re permissions [@shamoon](https://github.com/shamoon) ([#3697](https://github.com/paperless-ngx/paperless-ngx/pull/3697))
### Maintenance
- Chore: Updates codecov configuration for the flag settings and notification delay [@stumpylog](https://github.com/stumpylog) ([#3656](https://github.com/paperless-ngx/paperless-ngx/pull/3656))
### All App Changes
<details>
<summary>4 changes</summary>
- Fix: prevent button wrapping when sidebar narrows in MS Edge [@shamoon](https://github.com/shamoon) ([#3682](https://github.com/paperless-ngx/paperless-ngx/pull/3682))
- Fix: Handling for filenames with non-ascii and no content attribute [@stumpylog](https://github.com/stumpylog) ([#3695](https://github.com/paperless-ngx/paperless-ngx/pull/3695))
- Fix: Generation of thumbnails for existing stored emails [@stumpylog](https://github.com/stumpylog) ([#3696](https://github.com/paperless-ngx/paperless-ngx/pull/3696))
- Fix: Use row gap for filter editor [@kleinweby](https://github.com/kleinweby) ([#3662](https://github.com/paperless-ngx/paperless-ngx/pull/3662))
</details>
## paperless-ngx 1.16.3
### Bug Fixes
- Fix: Set user and home environment through supervisord [@stumpylog](https://github.com/stumpylog) ([#3638](https://github.com/paperless-ngx/paperless-ngx/pull/3638))
- Fix: Ignore errors when trying to copy the original file's stats [@stumpylog](https://github.com/stumpylog) ([#3652](https://github.com/paperless-ngx/paperless-ngx/pull/3652))
- Fix: Copy default thumbnail if thumbnail generation fails [@plu](https://github.com/plu) ([#3632](https://github.com/paperless-ngx/paperless-ngx/pull/3632))
- Fix: Set user and home environment through supervisord [@stumpylog](https://github.com/stumpylog) ([#3638](https://github.com/paperless-ngx/paperless-ngx/pull/3638))
- Fix: Fix quick install with external database not being fully ready [@stumpylog](https://github.com/stumpylog) ([#3637](https://github.com/paperless-ngx/paperless-ngx/pull/3637))
### Maintenance
- Chore: Update default Postgres version for new installs [@stumpylog](https://github.com/stumpylog) ([#3640](https://github.com/paperless-ngx/paperless-ngx/pull/3640))
### All App Changes
<details>
<summary>2 changes</summary>
- Fix: Ignore errors when trying to copy the original file's stats [@stumpylog](https://github.com/stumpylog) ([#3652](https://github.com/paperless-ngx/paperless-ngx/pull/3652))
- Fix: Copy default thumbnail if thumbnail generation fails [@plu](https://github.com/plu) ([#3632](https://github.com/paperless-ngx/paperless-ngx/pull/3632))
</details>
## paperless-ngx 1.16.2
### Bug Fixes
- Fix: Increase httpx operation timeouts to 30s [@stumpylog](https://github.com/stumpylog) ([#3627](https://github.com/paperless-ngx/paperless-ngx/pull/3627))
- Fix: Better error handling and checking when parsing documents via Tika [@stumpylog](https://github.com/stumpylog) ([#3617](https://github.com/paperless-ngx/paperless-ngx/pull/3617))
### Development
- Development: frontend unit testing [@shamoon](https://github.com/shamoon) ([#3597](https://github.com/paperless-ngx/paperless-ngx/pull/3597))
### Maintenance
- Chore: Bumps the CI/Docker pipenv version [@stumpylog](https://github.com/stumpylog) ([#3622](https://github.com/paperless-ngx/paperless-ngx/pull/3622))
- Chore: Set CI artifact retention days [@stumpylog](https://github.com/stumpylog) ([#3621](https://github.com/paperless-ngx/paperless-ngx/pull/3621))
### All App Changes
<details>
<summary>3 changes</summary>
- Fix: Increase httpx operation timeouts to 30s [@stumpylog](https://github.com/stumpylog) ([#3627](https://github.com/paperless-ngx/paperless-ngx/pull/3627))
- Fix: Better error handling and checking when parsing documents via Tika [@stumpylog](https://github.com/stumpylog) ([#3617](https://github.com/paperless-ngx/paperless-ngx/pull/3617))
- Development: frontend unit testing [@shamoon](https://github.com/shamoon) ([#3597](https://github.com/paperless-ngx/paperless-ngx/pull/3597))
</details>
## paperless-ngx 1.16.1
### Bug Fixes

View File

@@ -35,6 +35,12 @@ matcher.
Defaults to `redis://localhost:6379`.
`PAPERLESS_REDIS_PREFIX=<prefix>`
: Prefix to be used in Redis for keys and channels. Useful for sharing one Redis server among multiple Paperless instances.
Defaults to no prefix.
### Database
`PAPERLESS_DBENGINE=<engine_name>`
@@ -495,6 +501,19 @@ HTTP header/value expected by Django, eg `'["HTTP_X_FORWARDED_PROTO", "https"]'`
Settings this value has security implications. Read the Django documentation
and be sure you understand its usage before setting it.
`PAPERLESS_EMAIL_CERTIFICATE_FILE=<path>`
: Configures an additional SSL certificate file containing a [certificate](https://docs.python.org/3/library/ssl.html#certificates)
or certificate chain which should be trusted for validating SSL connections against mail providers.
This is for use with self-signed certificates against local IMAP servers.
Defaults to None.
!!! warning
Settings this value has security implications for the security of your email.
Understand what it does and be sure you need to before setting.
## OCR settings {#ocr}
Paperless uses [OCRmyPDF](https://ocrmypdf.readthedocs.io/en/latest/)
@@ -524,7 +543,7 @@ parsing documents.
`PAPERLESS_OCR_MODE=<mode>`
: Tell paperless when and how to perform ocr on your documents. Four
: Tell paperless when and how to perform ocr on your documents. Three
modes are available:
- `skip`: Paperless skips all pages and will perform ocr only on
@@ -1095,6 +1114,64 @@ barcode.
Defaults to "ASN"
`PAPERLESS_CONSUMER_BARCODE_UPSCALE=<float>`
: Defines the upscale factor used in barcode detection.
Improves the detection of small barcodes, i.e. with a value of 1.5 by
upscaling the document beforce the detection process. Upscaling will
only take place if value is bigger than 1.0. Otherwise upscaling will
not be performed to save resources. Try using in combination with
PAPERLESS_CONSUMER_BARCODE_DPI set to a value higher than default.
Defaults to 0.0
`PAPERLESS_CONSUMER_BARCODE_DPI=<int>`
: During barcode detection every page from a PDF document needs
to be converted to an image. A dpi value can be specified in the
conversion process. Default is 300. If the detection of small barcodes
fails a bigger dpi value i.e. 600 can fix the issue. Try using in
combination with PAPERLESS_CONSUMER_BARCODE_UPSCALE bigger than 1.0.
Defaults to "300"
## Collate Double-Sided Documents {#collate}
`PAPERLESS_CONSUMER_ENABLE_COLLATE_DOUBLE_SIDED=<bool>`
: Enables automatic collation of two single-sided scans into a double-sided
document.
This is useful if you have an automatic document feeder that only supports
single-sided scans, but you need to scan a double-sided document. If your
ADF supports double-sided scans natively, you do not need this feature.
`PAPERLESS_CONSUMER_RECURSIVE` must be enabled for this to work.
For more information, read the [corresponding section in the advanced
documentation](/advanced_usage#collate).
Defaults to false.
`PAPERLESS_CONSUMER_COLLATE_DOUBLE_SIDED_SUBDIR_NAME=<str>`
: The name of the subdirectory that the collate feature expects documents to
arrive.
This only has an effect if `PAPERLESS_CONSUMER_ENABLE_COLLATE_DOUBLE_SIDED`
has been enabled. Note that Paperless will not automatically create the
directory.
Defaults to "double-sided".
`PAPERLESS_CONSUMER_COLLATE_DOUBLE_SIDED_TIFF_SUPPORT=<bool>`
: Whether TIFF image files should be supported when collating documents.
This will automatically convert any TIFF image(s) to pdfs for later
processing. This only has an effect if
`PAPERLESS_CONSUMER_ENABLE_COLLATE_DOUBLE_SIDED` has been enabled.
Defaults to false.
## Binaries
There are a few external software packages that Paperless expects to
@@ -1102,7 +1179,7 @@ find on your system when it starts up. Unless you've done something
creative with their installation, you probably won't need to edit any
of these. However, if you've installed these programs somewhere where
simply typing the name of the program doesn't automatically execute it
(ie. the program isn't in your \$PATH), then you'll need to specify
(ie. the program isn't in your $PATH), then you'll need to specify
the literal path for that program.
`PAPERLESS_CONVERT_BINARY=<path>`
@@ -1186,7 +1263,7 @@ actual group ID on the host system, which you can get by executing
with English, German, Italian, Spanish and French. If your language
is not in this list, install additional languages with this
configuration option. You will need to [find the right LangCodes](https://tesseract-ocr.github.io/tessdoc/Data-Files-in-different-versions.html)
but note that (tesseract-ocr-\* package names)[https://packages.debian.org/bullseye/graphics/]
but note that [tesseract-ocr-\* package names](https://packages.debian.org/bullseye/graphics/)
do not always correspond with the language codes e.g. "chi_tra" should be
specified as "chi-tra".

View File

@@ -58,7 +58,7 @@ first-time setup.
!!! note
Every command is executed directly from the root folder of the project unless specified otherwise.
Every command is executed directly from the root folder of the project unless specified otherwise.
1. Install prerequisites + pipenv as mentioned in
[Bare metal route](/setup#bare_metal).
@@ -177,68 +177,69 @@ The front end is built using AngularJS. In order to get started, you need Node.j
The following commands are all performed in the `src-ui`-directory. You will need a running back end (including an active session) to connect to the back end API. To spin it up refer to the commands under the section [above](#back-end-development).
1. Install the Angular CLI. You might need sudo privileges
to perform this command:
1. Install the Angular CLI. You might need sudo privileges to perform this command:
```bash
$ npm install -g @angular/cli
```
```bash
$ npm install -g @angular/cli
```
2. Make sure that it's on your path.
2. Make sure that it's on your path.
3. Install all necessary modules:
3. Install all necessary modules:
```bash
$ npm install
```
```bash
$ npm install
```
4. You can launch a development server by running:
4. You can launch a development server by running:
```bash
$ ng serve
```
```bash
$ ng serve
```
This will automatically update whenever you save. However, in-place
compilation might fail on syntax errors, in which case you need to
restart it.
This will automatically update whenever you save. However, in-place
compilation might fail on syntax errors, in which case you need to
restart it.
By default, the development server is available on `http://localhost:4200/` and is configured to access the API at
`http://localhost:8000/api/`, which is the default of the backend. If you enabled `DEBUG` on the back end, several security overrides for allowed hosts, CORS and X-Frame-Options are in place so that the front end behaves exactly as in production.
By default, the development server is available on `http://localhost:4200/` and is configured to access the API at
`http://localhost:8000/api/`, which is the default of the backend. If you enabled `DEBUG` on the back end, several security overrides for allowed hosts, CORS and X-Frame-Options are in place so that the front end behaves exactly as in production.
### Testing and code style
- The front end code (.ts, .html, .scss) use `prettier` for code
formatting via the Git `pre-commit` hooks which run automatically on
commit. See [above](#code-formatting-with-pre-commit-hooks) for installation instructions. You can also run this via the CLI with a
command such as
The front end code (.ts, .html, .scss) use `prettier` for code
formatting via the Git `pre-commit` hooks which run automatically on
commit. See [above](#code-formatting-with-pre-commit-hooks) for installation instructions. You can also run this via the CLI with a
command such as
```bash
$ git ls-files -- '*.ts' | xargs pre-commit run prettier --files
```
```bash
$ git ls-files -- '*.ts' | xargs pre-commit run prettier --files
```
- Front end testing uses Jest and Playwright. Unit tests and e2e tests,
respectively, can be run non-interactively with:
Front end testing uses Jest and Playwright. Unit tests and e2e tests,
respectively, can be run non-interactively with:
```bash
$ ng test
$ npx playwright test
```
```bash
$ ng test
$ npx playwright test
```
- Playwright also includes a UI which can be run with:
Playwright also includes a UI which can be run with:
```bash
$ npx playwright test --ui
```
```bash
$ npx playwright test --ui
```
- In order to build the front end and serve it as part of Django, execute:
### Building the frontend
```bash
$ ng build --configuration production
```
In order to build the front end and serve it as part of Django, execute:
This will build the front end and put it in a location from which the
Django server will serve it as static content. This way, you can verify
that authentication is working.
```bash
$ ng build --configuration production
```
This will build the front end and put it in a location from which the
Django server will serve it as static content. This way, you can verify
that authentication is working.
## Localization

View File

@@ -3,10 +3,11 @@
## _What's the general plan for Paperless-ngx?_
**A:** While Paperless-ngx is already considered largely
"feature-complete" it is a community-driven project and development
will be guided in this way. New features can be submitted via GitHub
discussions and "up-voted" by the community but this is not a
guarantee the feature will be implemented. This project will always be
"feature-complete", it is a community-driven project and development
will be guided in this way. New features can be submitted via
[GitHub discussions](https://github.com/paperless-ngx/paperless-ngx/discussions)
and "up-voted" by the community, but this is not a
guarantee that the feature will be implemented. This project will always be
open to collaboration in the form of PRs, ideas etc.
## _I'm using docker. Where are my documents?_
@@ -58,7 +59,7 @@ elsewhere. Here are a couple notes about that.
WebP images are processed with OCR and converted into PDF documents.
- Plain text documents are supported as well and are added verbatim to
paperless.
- With the optional Tika integration enabled (see [Tika configuration](/configuration#tika),
- With the optional Tika integration enabled (see [Tika configuration](https://docs.paperless-ngx.com/configuration#tika)),
Paperless also supports various Office documents (.docx, .doc, odt,
.ppt, .pptx, .odp, .xls, .xlsx, .ods).
@@ -82,7 +83,7 @@ has to do much less work to serve the data.
## _How do I install paperless-ngx on Raspberry Pi?_
**A:** Docker images are available for armv7 and arm64 hardware, so just
follow the docker-compose instructions. Apart from more required disk
follow the [docker-compose instructions](https://docs.paperless-ngx.com/setup/#installation). Apart from more required disk
space compared to a bare metal installation, docker comes with close to
zero overhead, even on Raspberry Pi.

View File

@@ -259,6 +259,7 @@ supported.
- `python3-pip`
- `python3-dev`
- `default-libmysqlclient-dev` for MariaDB
- `pkg-config` for mysqlclient (python dependency)
- `fonts-liberation` for generating thumbnails for plain text
files
- `imagemagick` >= 6 for PDF conversion
@@ -273,7 +274,7 @@ supported.
Use this list for your preferred package management:
```
python3 python3-pip python3-dev imagemagick fonts-liberation gnupg libpq-dev default-libmysqlclient-dev libmagic-dev mime-support libzbar0 poppler-utils
python3 python3-pip python3-dev imagemagick fonts-liberation gnupg libpq-dev default-libmysqlclient-dev pkg-config libmagic-dev mime-support libzbar0 poppler-utils
```
These dependencies are required for OCRmyPDF, which is used for text

View File

@@ -345,3 +345,11 @@ STATEMENT: INSERT INTO "documents_tag" ("owner_id", "name", "match", "matching_
This can happen during heavy consumption when using polling. Paperless will handle it correctly and the file
will still be consumed
## Consumption fails with "Ghostscript PDF/A rendering failed"
Newer versions of OCRmyPDF will fail if it encounters errors during processing.
This is intentional as the output archive file may differ in unexpected or undesired
ways from the original. As the logs indicate, if you encounter this error you can set
`PAPERLESS_OCR_USER_ARGS: '{"continue_on_soft_render_error": true}'` to try to 'force'
processing documents with this issue.

View File

@@ -221,9 +221,18 @@ As of version 1.14.0 Paperless-ngx added core support for user / group permissio
based around 'global' permissions as well as 'object-level' permissions. Global permissions designate
which parts of the application a user can access (e.g. Documents, Tags, Settings) and object-level
determine which objects are visible or editable. All objects have an 'owner' and 'view' and 'edit'
permissions which can be granted to other users or groups.
permissions which can be granted to other users or groups. The paperless-ngx permissions system uses
the built-in user model of the backend framework, Django.
Permissions uses the built-in user model of the backend framework, Django.
!!! tip
Object-level permissions only apply to the object itself. In other words, setting permissions
for a Tag will _not_ affect the permissions of documents that have the Tag.
Permissions can be set using the new "Permissions" tab when editing documents, or bulk-applied
in the UI by selecting documents and choosing the "Permissions" button. Owner can also optionally
be set for documents uploaded via the API. Documents consumed via the consumption dir currently
do not have an owner set.
!!! note
@@ -238,11 +247,6 @@ Permissions uses the built-in user model of the backend framework, Django.
Note that superusers have access to all objects.
Permissions can be set using the new "Permissions" tab when editing documents, or bulk-applied
in the UI by selecting documents and choosing the "Permissions" button. Owner can also optionally
be set for documents uploaded via the API. Documents consumed via the consumption dir currently
do not have an owner set.
### Users and Groups
Paperless-ngx versions after 1.14.0 allow creating and editing users and groups via the 'frontend' UI.

View File

@@ -72,7 +72,7 @@ fi
if ! docker stats --no-stream &> /dev/null ; then
echo ""
echo "WARN: It look like the current user does not have Docker permissions."
echo "WARN: Use 'sudo usermod -aG docker $USER' to assign Docker permissions to the user."
echo "WARN: Use 'sudo usermod -aG docker $USER' to assign Docker permissions to the user (may require restarting shell)."
echo ""
sleep 3
fi
@@ -384,6 +384,14 @@ fi
${DOCKER_COMPOSE_CMD} pull
if [ "$DATABASE_BACKEND" == "postgres" ] || [ "$DATABASE_BACKEND" == "mariadb" ] ; then
echo "Starting DB first for initilzation"
${DOCKER_COMPOSE_CMD} up --detach db
# hopefully enough time for even the slower systems
sleep 15
${DOCKER_COMPOSE_CMD} stop
fi
${DOCKER_COMPOSE_CMD} run --rm -e DJANGO_SUPERUSER_PASSWORD="$PASSWORD" webserver createsuperuser --noinput --username "$USERNAME" --email "$EMAIL"
${DOCKER_COMPOSE_CMD} up --detach

View File

@@ -66,6 +66,11 @@
#PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=false
#PAPERLESS_CONSUMER_ENABLE_BARCODES=false
#PAPERLESS_CONSUMER_BARCODE_STRING=PATCHT
#PAPERLESS_CONSUMER_BARCODE_UPSCALE=0.0
#PAPERLESS_CONSUMER_BARCODE_DPI=300
#PAPERLESS_CONSUMER_ENABLE_COLLATE_DOUBLE_SIDED=false
#PAPERLESS_CONSUMER_COLLATE_DOUBLE_SIDED_SUBDIR_NAME=double-sided
#PAPERLESS_CONSUMER_COLLATE_DOUBLE_SIDED_TIFF_SUPPORT=false
#PAPERLESS_PRE_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh
#PAPERLESS_POST_CONSUME_SCRIPT=/path/to/an/arbitrary/script.sh
#PAPERLESS_FILENAME_DATE_ORDER=YMD

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:13
docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:15
docker run -d -p 6379:6379 redis:latest
docker run -p 3000:3000 -d gotenberg/gotenberg:7.8 gotenberg --chromium-disable-javascript=true --chromium-allow-list="file:///tmp/.*"
docker run -p 9998:9998 -d ghcr.io/paperless-ngx/tika:latest

View File

@@ -34,10 +34,12 @@
"pt-PT": "src/locale/messages.pt_PT.xlf",
"ro-RO": "src/locale/messages.ro_RO.xlf",
"ru-RU": "src/locale/messages.ru_RU.xlf",
"sk-SK": "src/locale/messages.sk_SK.xlf",
"sl-SI": "src/locale/messages.sl_SI.xlf",
"sr-CS": "src/locale/messages.sr_CS.xlf",
"sv-SE": "src/locale/messages.sv_SE.xlf",
"tr-TR": "src/locale/messages.tr_TR.xlf",
"uk-UA": "src/locale/messages.uk_UA.xlf",
"zh-CN": "src/locale/messages.zh_CN.xlf"
}
},
@@ -159,7 +161,6 @@
}
}
},
"defaultProject": "paperless-ui",
"cli": {
"schematicCollections": [
"@angular-eslint/schematics"

View File

@@ -94,51 +94,6 @@ test('should show a list of notes', async ({ page }) => {
).toHaveCount(4)
})
test('should support note deletion', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/documents/175/notes')
await expect(page.locator('app-document-notes')).toBeVisible()
const deletePromise = page.waitForRequest(
(request) =>
request.method() === 'DELETE' &&
request.url().includes('/api/documents/175/notes/')
)
await page
.getByRole('button', { name: /delete note/i, includeHidden: true })
.first()
.click()
await deletePromise
})
test('should support note insertion', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/documents/175/notes')
await expect(page.locator('app-document-notes')).toBeVisible()
await expect(
await page.getByRole('button', {
name: /delete note/i,
includeHidden: true,
})
).toHaveCount(4)
await page.getByPlaceholder('Enter note').fill('This is a new note')
const addPromise = page.waitForRequest((request) => {
if (!request.url().includes('/notes/')) {
// ignore other requests
return true
} else {
const data = request.postDataJSON()
const isValid = data['note'] === 'This is a new note'
return (
isValid &&
request.method() === 'POST' &&
request.url().includes('/notes/')
)
}
})
await page.getByRole('button', { name: 'Add note' }).click()
await addPromise
})
test('should support quick filters', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
await page.goto('/documents/175/details')

View File

@@ -1,58 +0,0 @@
import { test, expect } from '@playwright/test'
const REQUESTS_HAR1 = 'e2e/manage/requests/api-manage1.har'
const REQUESTS_HAR2 = 'e2e/manage/requests/api-manage2.har'
test('should show a list of tags with bottom pagination as well', async ({
page,
}) => {
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
await page.goto('/tags')
await expect(page.getByRole('main')).toHaveText(/26 total tags/i)
await expect(await page.locator('ngb-pagination')).toHaveCount(2)
})
test('should show a list of correspondents without bottom pagination', async ({
page,
}) => {
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
await page.goto('/correspondents')
await expect(page.getByRole('main')).toHaveText(/4 total correspondents/i)
await expect(await page.locator('ngb-pagination')).toHaveCount(1)
})
test('should support quick filter Documents button', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
await page.goto('/tags')
await page
.getByRole('row', { name: 'Inbox' })
.getByRole('button', { name: 'Documents' })
.click()
await expect(page).toHaveURL(/tags__id__all=9/)
})
test('should support item editing', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
await page.goto('/tags')
await page
.getByRole('row', { name: 'Inbox' })
.getByRole('button', { name: 'Edit' })
.click()
await expect(page.getByRole('dialog')).toBeVisible()
await expect(page.getByLabel('Name')).toHaveValue('Inbox')
await page.getByTitle('Color').getByRole('button').click()
const color = await page.getByLabel('Color').inputValue()
const updatePromise = page.waitForRequest((request) => {
const data = request.postDataJSON()
const isValid = data['color'] === color
return (
isValid &&
request.method() === 'PUT' &&
request.url().includes('/api/tags/9/')
)
})
await page.getByRole('button', { name: 'Save' }).click()
await updatePromise
})

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,6 @@
import { test, expect } from '@playwright/test'
const REQUESTS_HAR = 'e2e/settings/requests/api-settings.har'
const REQUESTS_HAR2 = 'e2e/settings/requests/api-settings2.har'
const REQUESTS_HAR3 = 'e2e/settings/requests/api-settings3.har'
test('should post settings on save', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
@@ -101,65 +99,3 @@ test('should support tab direct navigation', async ({ page }) => {
page.getByRole('tab', { name: 'Users & Groups' })
).toHaveAttribute('aria-selected', 'true')
})
test('should show a list of mail accounts & support creation', async ({
page,
}) => {
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
await page.goto('/settings/mail')
await expect(
page.getByRole('listitem').filter({ hasText: 'imap.gmail.com' })
).toHaveCount(1)
await expect(
page.getByRole('listitem').filter({ hasText: 'imap.domain.com' })
).toHaveCount(1)
await page.getByRole('button', { name: /Add Account/ }).click()
await expect(page.getByRole('dialog')).toHaveCount(1)
await page.getByLabel('Name', { exact: true }).fill('Test Account')
await page.getByLabel('IMAP Server', { exact: true }).fill('imap.server.com')
await page.getByLabel('IMAP Port', { exact: true }).fill('993')
await page.getByLabel('Username', { exact: true }).fill('username')
await page.getByLabel('Password', { exact: true }).fill('password')
const createPromise = page.waitForRequest((request) => {
const data = request.postDataJSON()
const isValid = data['imap_server'] === 'imap.server.com'
return (
isValid &&
request.method() === 'POST' &&
request.url().includes('/api/mail_accounts/')
)
})
await page.getByRole('button', { name: 'Save' }).click()
await createPromise
})
test('should show a list of mail rules & support creation', async ({
page,
}) => {
await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' })
await page.goto('/settings/mail')
await expect(
page.getByRole('listitem').filter({ hasText: 'domain' })
).toHaveCount(2)
await expect(
page.getByRole('listitem').filter({ hasText: 'gmail' })
).toHaveCount(2)
await page.getByRole('button', { name: /Add Rule/ }).click()
await expect(page.getByRole('dialog')).toHaveCount(1)
await page.getByLabel('Name', { exact: true }).fill('Test Rule')
await page.getByTitle('Account').locator('span').first().click()
await page.getByRole('option', { name: 'gmail' }).click()
await page.getByLabel('Maximum age (days)').fill('0')
const createPromise = page.waitForRequest((request) => {
const data = request.postDataJSON()
const isValid = data['name'] === 'Test Rule'
return (
isValid &&
request.method() === 'POST' &&
request.url().includes('/api/mail_rules/')
)
})
await page.getByRole('button', { name: 'Save' }).scrollIntoViewIfNeeded()
await page.getByRole('button', { name: 'Save' }).click()
await createPromise
})

File diff suppressed because one or more lines are too long

View File

@@ -1,71 +0,0 @@
import { test, expect } from '@playwright/test'
const REQUESTS_HAR = 'e2e/tasks/requests/api-tasks.har'
test('should show a list of dismissable tasks in tabs', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/tasks')
await expect(page.getByRole('tab', { name: /Failed/ })).toHaveText(/1/)
await expect(
page.getByRole('cell').filter({ hasText: 'Dismiss' })
).toHaveCount(1)
await expect(page.getByRole('tab', { name: /Complete/ })).toHaveText(/8/)
await page.getByRole('tab', { name: /Complete/ }).click()
await expect(
page.getByRole('cell').filter({ hasText: 'Dismiss' })
).toHaveCount(8)
await page.getByRole('tab', { name: /Started/ }).click()
await expect(
page.getByRole('cell').filter({ hasText: 'Dismiss' })
).toHaveCount(0)
await page.getByRole('tab', { name: /Queued/ }).click()
await expect(
page.getByRole('cell').filter({ hasText: 'Dismiss' })
).toHaveCount(0)
})
test('should support dismissing tasks', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/tasks')
await page.getByRole('tab', { name: /Failed/ }).click()
const dismissPromise = page.waitForRequest((request) => {
const data = request.postDataJSON()
const isValid = Array.isArray(data['tasks']) && data['tasks'].includes(255)
return (
isValid &&
request.method() === 'POST' &&
request.url().includes('/api/acknowledge_tasks/')
)
})
await page
.getByRole('button', { name: 'Dismiss', exact: true })
.first()
.click()
await dismissPromise
})
test('should support dismiss all tasks', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/tasks')
await expect(page.getByRole('button', { name: 'Dismiss all' })).toBeEnabled()
await page.getByRole('button', { name: 'Dismiss all' }).click()
const dismissPromise = page.waitForRequest((request) => {
const data = request.postDataJSON()
const isValid = Array.isArray(data['tasks'])
return (
isValid &&
request.method() === 'POST' &&
request.url().includes('/api/acknowledge_tasks/')
)
})
await page.getByRole('button', { name: /Dismiss/ }).click()
await dismissPromise
})
test('should warn on dismiss all tasks', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/tasks')
await expect(page.getByRole('button', { name: 'Dismiss all' })).toBeEnabled()
await page.getByRole('button', { name: 'Dismiss all' }).click()
await expect(page.getByRole('dialog')).toHaveCount(1)
})

File diff suppressed because it is too large Load Diff

8942
src-ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,54 +10,54 @@
},
"private": true,
"dependencies": {
"@angular/common": "~15.2.8",
"@angular/compiler": "~15.2.8",
"@angular/core": "~15.2.8",
"@angular/forms": "~15.2.8",
"@angular/localize": "~15.2.8",
"@angular/platform-browser": "~15.2.8",
"@angular/platform-browser-dynamic": "~15.2.8",
"@angular/router": "~15.2.8",
"@ng-bootstrap/ng-bootstrap": "^14.2.0",
"@ng-select/ng-select": "^10.0.4",
"@angular/common": "~16.1.7",
"@angular/compiler": "~16.1.7",
"@angular/core": "~16.1.7",
"@angular/forms": "~16.1.7",
"@angular/localize": "~16.1.7",
"@angular/platform-browser": "~16.1.7",
"@angular/platform-browser-dynamic": "~16.1.7",
"@angular/router": "~16.1.7",
"@ng-bootstrap/ng-bootstrap": "^15.1.0",
"@ng-select/ng-select": "^11.1.1",
"@ngneat/dirty-check-forms": "^3.0.3",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.0",
"bootstrap": "^5.3.1",
"file-saver": "^2.0.5",
"mime-names": "^1.0.0",
"ng2-pdf-viewer": "^9.1.5",
"ngx-color": "^8.0.3",
"ngx-cookie-service": "^15.0.0",
"ngx-file-drop": "^15.0.0",
"ngx-ui-tour-ng-bootstrap": "^12.6.0",
"ng2-pdf-viewer": "^10.0.0",
"ngx-color": "^9.0.0",
"ngx-cookie-service": "^16.0.0",
"ngx-file-drop": "^16.0.0",
"ngx-ui-tour-ng-bootstrap": "^13.0.3",
"rxjs": "^7.8.1",
"tslib": "^2.5.2",
"tslib": "^2.6.1",
"uuid": "^9.0.0",
"zone.js": "^0.13.0"
},
"devDependencies": {
"@angular-builders/jest": "15.0.0",
"@angular-devkit/build-angular": "~15.2.6",
"@angular-eslint/builder": "15.2.1",
"@angular-eslint/eslint-plugin": "15.2.1",
"@angular-eslint/eslint-plugin-template": "15.2.1",
"@angular-eslint/schematics": "15.2.1",
"@angular-eslint/template-parser": "15.2.1",
"@angular/cli": "~15.2.7",
"@angular/compiler-cli": "~15.2.8",
"@playwright/test": "^1.35.1",
"@types/jest": "^29.5.0",
"@types/node": "^20.2.5",
"@typescript-eslint/eslint-plugin": "^5.59.8",
"@typescript-eslint/parser": "^5.59.8",
"@angular-builders/jest": "16.0.0",
"@angular-devkit/build-angular": "~16.1.6",
"@angular-eslint/builder": "16.1.0",
"@angular-eslint/eslint-plugin": "16.1.0",
"@angular-eslint/eslint-plugin-template": "16.1.0",
"@angular-eslint/schematics": "16.1.0",
"@angular-eslint/template-parser": "16.1.0",
"@angular/cli": "~16.1.6",
"@angular/compiler-cli": "~16.1.3",
"@playwright/test": "^1.36.2",
"@types/jest": "^29.5.3",
"@types/node": "^20.4.5",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"concurrently": "^8.1.0",
"eslint": "^8.41.0",
"jest": "28.1.3",
"jest-environment-jsdom": "^29.5.0",
"jest-preset-angular": "^12.2.6",
"eslint": "^8.46.0",
"jest": "29.6.2",
"jest-environment-jsdom": "^29.6.2",
"jest-preset-angular": "^13.1.1",
"jest-websocket-mock": "^2.4.0",
"ts-node": "~10.9.1",
"typescript": "~4.9.5",
"typescript": "^5.1.6",
"wait-on": "^7.0.1"
}
}

View File

@@ -25,10 +25,12 @@ import localePl from '@angular/common/locales/pl'
import localePt from '@angular/common/locales/pt'
import localeRo from '@angular/common/locales/ro'
import localeRu from '@angular/common/locales/ru'
import localeSk from '@angular/common/locales/sk'
import localeSl from '@angular/common/locales/sl'
import localeSr from '@angular/common/locales/sr'
import localeSv from '@angular/common/locales/sv'
import localeTr from '@angular/common/locales/tr'
import localeUk from '@angular/common/locales/uk'
import localeZh from '@angular/common/locales/zh'
registerLocaleData(localeAr)
@@ -49,10 +51,12 @@ registerLocaleData(localePt, 'pt-BR')
registerLocaleData(localePt, 'pt-PT')
registerLocaleData(localeRo)
registerLocaleData(localeRu)
registerLocaleData(localeSk)
registerLocaleData(localeSl)
registerLocaleData(localeSr)
registerLocaleData(localeSv)
registerLocaleData(localeTr)
registerLocaleData(localeUk)
registerLocaleData(localeZh)
/* global mocks for jsdom */
@@ -74,15 +78,6 @@ Object.defineProperty(window, 'getComputedStyle', {
Object.defineProperty(window, 'ResizeObserver', { value: mock() })
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
}
},
})
HTMLCanvasElement.prototype.getContext = <
typeof HTMLCanvasElement.prototype.getContext
>jest.fn()

View File

@@ -139,104 +139,88 @@ export class AppComponent implements OnInit, OnDestroy {
const nextBtnTitle = $localize`Next`
const endBtnTitle = $localize`End`
this.tourService.initialize([
this.tourService.initialize(
[
{
anchorId: 'tour.dashboard',
content: $localize`The dashboard can be used to show saved views, such as an 'Inbox'. Those settings are found under Settings > Saved Views once you have created some.`,
route: '/dashboard',
delayAfterNavigation: 500,
isOptional: false,
},
{
anchorId: 'tour.upload-widget',
content: $localize`Drag-and-drop documents here to start uploading or place them in the consume folder. You can also drag-and-drop documents anywhere on all other pages of the web app. Once you do, Paperless-ngx will start training its machine learning algorithms.`,
route: '/dashboard',
},
{
anchorId: 'tour.documents',
content: $localize`The documents list shows all of your documents and allows for filtering as well as bulk-editing. There are three different view styles: list, small cards and large cards. A list of documents currently opened for editing is shown in the sidebar.`,
route: '/documents?sort=created&reverse=1&page=1',
delayAfterNavigation: 500,
placement: 'bottom',
},
{
anchorId: 'tour.documents-filter-editor',
content: $localize`The filtering tools allow you to quickly find documents using various searches, dates, tags, etc.`,
route: '/documents?sort=created&reverse=1&page=1',
placement: 'bottom',
},
{
anchorId: 'tour.documents-views',
content: $localize`Any combination of filters can be saved as a 'view' which can then be displayed on the dashboard and / or sidebar.`,
route: '/documents?sort=created&reverse=1&page=1',
},
{
anchorId: 'tour.tags',
content: $localize`Tags, correspondents, document types and storage paths can all be managed using these pages. They can also be created from the document edit view.`,
route: '/tags',
backdropConfig: {
offset: 0,
},
},
{
anchorId: 'tour.file-tasks',
content: $localize`File Tasks shows you documents that have been consumed, are waiting to be, or may have failed during the process.`,
route: '/tasks',
backdropConfig: {
offset: 0,
},
},
{
anchorId: 'tour.settings',
content: $localize`Check out the settings for various tweaks to the web app, toggle settings for saved views or setup e-mail checking.`,
route: '/settings',
backdropConfig: {
offset: 0,
},
},
{
anchorId: 'tour.outro',
title: $localize`Thank you! 🙏`,
content:
$localize`There are <em>tons</em> more features and info we didn't cover here, but this should get you started. Check out the documentation or visit the project on GitHub to learn more or to report issues.` +
'<br/><br/>' +
$localize`Lastly, on behalf of every contributor to this community-supported project, thank you for using Paperless-ngx!`,
route: '/dashboard',
isOptional: false,
backdropConfig: {
offset: 0,
},
},
],
{
anchorId: 'tour.dashboard',
content: $localize`The dashboard can be used to show saved views, such as an 'Inbox'. Those settings are found under Settings > Saved Views once you have created some.`,
route: '/dashboard',
enableBackdrop: true,
delayAfterNavigation: 500,
backdropConfig: {
offset: 10,
},
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.upload-widget',
content: $localize`Drag-and-drop documents here to start uploading or place them in the consume folder. You can also drag-and-drop documents anywhere on all other pages of the web app. Once you do, Paperless-ngx will start training its machine learning algorithms.`,
route: '/dashboard',
enableBackdrop: true,
isOptional: true,
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.documents',
content: $localize`The documents list shows all of your documents and allows for filtering as well as bulk-editing. There are three different view styles: list, small cards and large cards. A list of documents currently opened for editing is shown in the sidebar.`,
route: '/documents?sort=created&reverse=1&page=1',
delayAfterNavigation: 500,
placement: 'bottom',
enableBackdrop: true,
disableScrollToAnchor: true,
isOptional: true,
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.documents-filter-editor',
content: $localize`The filtering tools allow you to quickly find documents using various searches, dates, tags, etc.`,
route: '/documents?sort=created&reverse=1&page=1',
placement: 'bottom',
enableBackdrop: true,
isOptional: true,
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.documents-views',
content: $localize`Any combination of filters can be saved as a 'view' which can then be displayed on the dashboard and / or sidebar.`,
route: '/documents?sort=created&reverse=1&page=1',
enableBackdrop: true,
isOptional: true,
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.tags',
content: $localize`Tags, correspondents, document types and storage paths can all be managed using these pages. They can also be created from the document edit view.`,
route: '/tags',
enableBackdrop: true,
isOptional: true,
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.file-tasks',
content: $localize`File Tasks shows you documents that have been consumed, are waiting to be, or may have failed during the process.`,
route: '/tasks',
enableBackdrop: true,
isOptional: true,
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.settings',
content: $localize`Check out the settings for various tweaks to the web app, toggle settings for saved views or setup e-mail checking.`,
route: '/settings',
enableBackdrop: true,
isOptional: true,
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
{
anchorId: 'tour.outro',
title: $localize`Thank you! 🙏`,
content:
$localize`There are <em>tons</em> more features and info we didn't cover here, but this should get you started. Check out the documentation or visit the project on GitHub to learn more or to report issues.` +
'<br/><br/>' +
$localize`Lastly, on behalf of every contributor to this community-supported project, thank you for using Paperless-ngx!`,
route: '/dashboard',
prevBtnTitle,
nextBtnTitle,
endBtnTitle,
},
])
useLegacyTitle: true,
}
)
this.tourService.start$.subscribe(() => {
this.renderer.addClass(document.body, 'tour-active')

View File

@@ -92,6 +92,8 @@ import { PermissionsDialogComponent } from './components/common/permissions-dial
import { PermissionsFormComponent } from './components/common/input/permissions/permissions-form/permissions-form.component'
import { PermissionsFilterDropdownComponent } from './components/common/permissions-filter-dropdown/permissions-filter-dropdown.component'
import { UsernamePipe } from './pipes/username.pipe'
import { LogoComponent } from './components/common/logo/logo.component'
import { IsNumberPipe } from './pipes/is-number.pipe'
import localeAr from '@angular/common/locales/ar'
import localeBe from '@angular/common/locales/be'
@@ -110,10 +112,12 @@ import localePl from '@angular/common/locales/pl'
import localePt from '@angular/common/locales/pt'
import localeRo from '@angular/common/locales/ro'
import localeRu from '@angular/common/locales/ru'
import localeSk from '@angular/common/locales/sk'
import localeSl from '@angular/common/locales/sl'
import localeSr from '@angular/common/locales/sr'
import localeSv from '@angular/common/locales/sv'
import localeTr from '@angular/common/locales/tr'
import localeUk from '@angular/common/locales/uk'
import localeZh from '@angular/common/locales/zh'
registerLocaleData(localeAr)
@@ -134,10 +138,12 @@ registerLocaleData(localePt, 'pt-BR')
registerLocaleData(localePt, 'pt-PT')
registerLocaleData(localeRo)
registerLocaleData(localeRu)
registerLocaleData(localeSk)
registerLocaleData(localeSl)
registerLocaleData(localeSr)
registerLocaleData(localeSv)
registerLocaleData(localeTr)
registerLocaleData(localeUk)
registerLocaleData(localeZh)
function initializeApp(settings: SettingsService) {
@@ -217,6 +223,8 @@ function initializeApp(settings: SettingsService) {
PermissionsFormComponent,
PermissionsFilterDropdownComponent,
UsernamePipe,
LogoComponent,
IsNumberPipe,
],
imports: [
BrowserModule,

View File

@@ -137,6 +137,7 @@ main {
.sidebar .nav-link {
font-weight: 500;
white-space: nowrap;
&:hover, &.active, &:focus {
color: var(--bs-primary);

View File

@@ -22,7 +22,7 @@ export enum EditDialogMode {
@Directive()
export abstract class EditDialogComponent<
T extends ObjectWithPermissions | ObjectWithId
T extends ObjectWithPermissions | ObjectWithId,
> implements OnInit
{
constructor(

View File

@@ -9,7 +9,7 @@
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
</svg>
</button>
<button *ngIf="showFilter" class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="this.value === null" i18n-title title="Filter documents with this {{title}}">
<button *ngIf="showFilter" class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="this.value === null" title="{{ fitlerButtonTitle }}">
<svg class="buttonicon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#filter" />
</svg>

View File

@@ -98,4 +98,8 @@ export class DateComponent
onFilterDocuments() {
this.filterDocuments.emit([this.ngbDateParserFormatter.parse(this.value)])
}
get filterButtonTitle() {
return $localize`Filter documents with this ${this.title}`
}
}

View File

@@ -26,7 +26,7 @@
<use xlink:href="assets/bootstrap-icons.svg#plus" />
</svg>
</button>
<button *ngIf="showFilter" class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="isPrivate || this.value === null" i18n-title title="Filter documents with this {{title}}">
<button *ngIf="showFilter" class="btn btn-outline-secondary" type="button" (click)="onFilterDocuments()" [disabled]="isPrivate || this.value === null" title="{{ filterButtonTitle }}">
<svg class="buttonicon" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#filter" />
</svg>

View File

@@ -144,4 +144,8 @@ export class SelectComponent extends AbstractInputComponent<number> {
onFilterDocuments() {
this.filterDocuments.emit([this.items.find((i) => i.id === this.value)])
}
get filterButtonTitle() {
return $localize`Filter documents with this ${this.title}`
}
}

View File

@@ -2,7 +2,7 @@
<label class="form-label" for="tags" i18n>Tags</label>
<div class="input-group flex-nowrap">
<ng-select name="tags" [items]="tags" bindLabel="name" bindValue="id" [(ngModel)]="value"
<ng-select #tagSelect name="tags" [items]="tags" bindLabel="name" bindValue="id" [(ngModel)]="value"
[disabled]="disabled"
[multiple]="true"
[closeOnSelect]="false"
@@ -11,11 +11,7 @@
[addTag]="allowCreate ? createTagRef : false"
addTagText="Add tag"
i18n-addTagText
(change)="onChange(value)"
(search)="onSearch($event)"
(focus)="clearLastSearchTerm()"
(clear)="clearLastSearchTerm()"
(blur)="onBlur()">
(change)="onChange(value)">
<ng-template ng-label-tmp let-item="item">
<span class="tag-wrap tag-wrap-delete" (mousedown)="removeTag($event, item.id)">

View File

@@ -15,16 +15,28 @@ import {
DEFAULT_MATCHING_ALGORITHM,
MATCH_ALL,
} from 'src/app/data/matching-model'
import { NgSelectModule } from '@ng-select/ng-select'
import { NgSelectComponent, NgSelectModule } from '@ng-select/ng-select'
import { RouterTestingModule } from '@angular/router/testing'
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { of } from 'rxjs'
import { TagService } from 'src/app/services/rest/tag.service'
import {
NgbAccordionModule,
NgbModal,
NgbModalModule,
NgbModalRef,
NgbPopoverModule,
} from '@ng-bootstrap/ng-bootstrap'
import { TagEditDialogComponent } from '../../edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
import { CheckComponent } from '../check/check.component'
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
import { TextComponent } from '../text/text.component'
import { ColorComponent } from '../color/color.component'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { PermissionsFormComponent } from '../permissions/permissions-form/permissions-form.component'
import { SelectComponent } from '../select/select.component'
import { ColorSliderModule } from 'ngx-color/slider'
import { By } from '@angular/platform-browser'
const tags: PaperlessTag[] = [
{
@@ -56,12 +68,32 @@ describe('TagsComponent', () => {
beforeEach(async () => {
TestBed.configureTestingModule({
declarations: [TagsComponent],
declarations: [
TagsComponent,
TagEditDialogComponent,
TextComponent,
ColorComponent,
IfOwnerDirective,
SelectComponent,
TextComponent,
PermissionsFormComponent,
ColorComponent,
CheckComponent,
],
providers: [
{
provide: TagService,
useValue: {
listAll: () => of(tags),
listAll: () =>
of({
results: tags,
}),
create: () =>
of({
name: 'bar',
id: 99,
color: '#fff000',
}),
},
},
],
@@ -72,6 +104,8 @@ describe('TagsComponent', () => {
RouterTestingModule,
HttpClientTestingModule,
NgbModalModule,
NgbAccordionModule,
NgbPopoverModule,
],
}).compileComponents()
@@ -85,7 +119,7 @@ describe('TagsComponent', () => {
})
it('should support suggestions', () => {
expect(component.value).toBeUndefined()
expect(component.value).toHaveLength(0)
component.value = []
component.tags = tags
component.suggestions = [1, 2]
@@ -107,19 +141,19 @@ describe('TagsComponent', () => {
it('should support create new using last search term and open a modal', () => {
let activeInstances: NgbModalRef[]
modalService.activeInstances.subscribe((v) => (activeInstances = v))
component.onSearch({ term: 'bar' })
component.select.searchTerm = 'foobar'
component.createTag()
expect(modalService.hasOpenModals()).toBeTruthy()
expect(activeInstances[0].componentInstance.object.name).toEqual('bar')
expect(activeInstances[0].componentInstance.object.name).toEqual('foobar')
const editDialog = activeInstances[0]
.componentInstance as TagEditDialogComponent
editDialog.save() // create is mocked
fixture.detectChanges()
fixture.whenStable().then(() => {
expect(fixture.debugElement.nativeElement.textContent).toContain('foobar')
})
})
it('should clear search term on blur after delay', fakeAsync(() => {
const clearSpy = jest.spyOn(component, 'clearLastSearchTerm')
component.onBlur()
tick(3000)
expect(clearSpy).toHaveBeenCalled()
}))
it('support remove tags', () => {
component.tags = tags
component.value = [1, 2]
@@ -132,6 +166,7 @@ describe('TagsComponent', () => {
})
it('should get tags', () => {
component.tags = null
expect(component.getTag(2)).toBeNull()
component.tags = tags
expect(component.getTag(2)).toEqual(tags[1])

View File

@@ -5,6 +5,7 @@ import {
Input,
OnInit,
Output,
ViewChild,
} from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
@@ -12,6 +13,8 @@ import { PaperlessTag } from 'src/app/data/paperless-tag'
import { TagEditDialogComponent } from '../../edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
import { TagService } from 'src/app/services/rest/tag.service'
import { EditDialogMode } from '../../edit-dialog/edit-dialog.component'
import { first, firstValueFrom, tap } from 'rxjs'
import { NgSelectComponent } from '@ng-select/ng-select'
@Component({
providers: [
@@ -26,7 +29,10 @@ import { EditDialogMode } from '../../edit-dialog/edit-dialog.component'
styleUrls: ['./tags.component.scss'],
})
export class TagsComponent implements OnInit, ControlValueAccessor {
constructor(private tagService: TagService, private modalService: NgbModal) {
constructor(
private tagService: TagService,
private modalService: NgbModal
) {
this.createTagRef = this.createTag.bind(this)
}
@@ -71,14 +77,14 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
@Output()
filterDocuments = new EventEmitter<PaperlessTag[]>()
value: number[]
@ViewChild('tagSelect') select: NgSelectComponent
tags: PaperlessTag[]
value: number[] = []
tags: PaperlessTag[] = []
public createTagRef: (name) => void
private _lastSearchTerm: string
getTag(id: number) {
if (this.tags) {
return this.tags.find((tag) => tag.id == id)
@@ -108,15 +114,20 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
})
modal.componentInstance.dialogMode = EditDialogMode.CREATE
if (name) modal.componentInstance.object = { name: name }
else if (this._lastSearchTerm)
modal.componentInstance.object = { name: this._lastSearchTerm }
modal.componentInstance.succeeded.subscribe((newTag) => {
this.tagService.listAll().subscribe((tags) => {
this.tags = tags.results
this.value = [...this.value, newTag.id]
this.onChange(this.value)
})
})
else if (this.select.searchTerm)
modal.componentInstance.object = { name: this.select.searchTerm }
this.select.searchTerm = null
this.select.detectChanges()
return firstValueFrom(
(modal.componentInstance as TagEditDialogComponent).succeeded.pipe(
first(),
tap(() => {
this.tagService.listAll().subscribe((tags) => {
this.tags = tags.results
})
})
)
)
}
getSuggestions() {
@@ -134,20 +145,6 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
this.onChange(this.value)
}
clearLastSearchTerm() {
this._lastSearchTerm = null
}
onSearch($event) {
this._lastSearchTerm = $event.term
}
onBlur() {
setTimeout(() => {
this.clearLastSearchTerm()
}, 3000)
}
get hasPrivate(): boolean {
return this.value.some(
(t) => this.tags?.find((t2) => t2.id === t) === undefined

View File

@@ -0,0 +1,18 @@
<svg [class]="getClasses()" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2897.4 896.6" [attr.height]="height">
<path class="leaf" d="M140,713.7c-3.4-16.4-10.3-49.1-11.2-49.1c-145.7-87.1-128.4-238-80.2-324.2C59,449,251.2,524,139.1,656.8 c-0.9,1.7,5.2,22.4,10.3,41.4c22.4-37.9,56-83.6,54.3-87.9C65.9,273.9,496.9,248.1,586.6,39.4c40.5,201.8-20.7,513.9-367.2,593.2 c-1.7,0.9-62.9,108.6-65.5,109.5c0-1.7-25.9-0.9-22.4-9.5C133.1,727.4,136.6,720.6,140,713.7L140,713.7z M135.7,632.6 c44-50.9-7.8-137.9-38.8-166.4C149.5,556.7,146,609.3,135.7,632.6L135.7,632.6z" transform="translate(0)" style="fill:#17541f"/>
<g class="text" style="fill:#000">
<path d="M1022.3,428.7c-17.8-19.9-42.7-29.8-74.7-29.8c-22.3,0-42.4,5.7-60.5,17.3c-18.1,11.6-32.3,27.5-42.5,47.8 s-15.3,42.9-15.3,67.8c0,24.9,5.1,47.5,15.3,67.8c10.3,20.3,24.4,36.2,42.5,47.8c18.1,11.5,38.3,17.3,60.5,17.3 c32,0,56.9-9.9,74.7-29.8v20.4v0.2h84.5V408.3h-84.5V428.7z M1010.5,575c-10.2,11.7-23.6,17.6-40.2,17.6s-29.9-5.9-40-17.6 s-15.1-26.1-15.1-43.3c0-17.1,5-31.6,15.1-43.3s23.4-17.6,40-17.6c16.6,0,30,5.9,40.2,17.6s15.3,26.1,15.3,43.3 S1020.7,563.3,1010.5,575z" transform="translate(0)"/>
<path d="M1381,416.1c-18.1-11.5-38.3-17.3-60.5-17.4c-32,0-56.9,9.9-74.7,29.8v-20.4h-84.5v390.7h84.5v-164 c17.8,19.9,42.7,29.8,74.7,29.8c22.3,0,42.4-5.7,60.5-17.3s32.3-27.5,42.5-47.8c10.2-20.3,15.3-42.9,15.3-67.8s-5.1-47.5-15.3-67.8 C1413.2,443.6,1399.1,427.7,1381,416.1z M1337.9,575c-10.1,11.7-23.4,17.6-40,17.6s-29.9-5.9-40-17.6s-15.1-26.1-15.1-43.3 c0-17.1,5-31.6,15.1-43.3s23.4-17.6,40-17.6s29.9,5.9,40,17.6s15.1,26.1,15.1,43.3S1347.9,563.3,1337.9,575z" transform="translate(0)"/>
<path d="M1672.2,416.8c-20.5-12-43-18-67.6-18c-24.9,0-47.6,5.9-68,17.6c-20.4,11.7-36.5,27.7-48.2,48s-17.6,42.7-17.6,67.3 c0.3,25.2,6.2,47.8,17.8,68c11.5,20.2,28,36,49.3,47.6c21.3,11.5,45.9,17.3,73.8,17.3c48.6,0,86.8-14.7,114.7-44l-52.5-48.9 c-8.6,8.3-17.6,14.6-26.7,19c-9.3,4.3-21.1,6.4-35.3,6.4c-11.6,0-22.5-3.6-32.7-10.9c-10.3-7.3-17.1-16.5-20.7-27.8h180l0.4-11.6 c0-29.6-6-55.7-18-78.2S1692.6,428.8,1672.2,416.8z M1558.3,503.2c2.1-12.1,7.5-21.8,16.2-29.1s18.7-10.9,30-10.9 s21.2,3.6,29.8,10.9c8.6,7.2,13.9,16.9,16,29.1H1558.3z" transform="translate(0)"/>
<path d="M1895.3,411.7c-11,5.6-20.3,13.7-28,24.4h-0.1v-28h-84.5v247.3h84.5V536.3c0-22.6,4.7-38.1,14.2-46.5 c9.5-8.5,22.7-12.7,39.6-12.7c6.2,0,13.5,1,21.8,3.1l10.7-72c-5.9-3.3-14.5-4.9-25.8-4.9C1917.1,403.3,1906.3,406.1,1895.3,411.7z" transform="translate(0)"/>
<rect x="1985" y="277.4" width="84.5" height="377.8" transform="translate(0)"/>
<path d="M2313.2,416.8c-20.5-12-43-18-67.6-18c-24.9,0-47.6,5.9-68,17.6s-36.5,27.7-48.2,48c-11.7,20.3-17.6,42.7-17.6,67.3 c0.3,25.2,6.2,47.8,17.8,68c11.5,20.2,28,36,49.3,47.6c21.3,11.5,45.9,17.3,73.8,17.3c48.6,0,86.8-14.7,114.7-44l-52.5-48.9 c-8.6,8.3-17.6,14.6-26.7,19c-9.3,4.3-21.1,6.4-35.3,6.4c-11.6,0-22.5-3.6-32.7-10.9c-10.3-7.3-17.1-16.5-20.7-27.8h180l0.4-11.6 c0-29.6-6-55.7-18-78.2S2333.6,428.8,2313.2,416.8z M2199.3,503.2c2.1-12.1,7.5-21.8,16.2-29.1s18.7-10.9,30-10.9 s21.2,3.6,29.8,10.9c8.6,7.2,13.9,16.9,16,29.1H2199.3z" transform="translate(0)"/>
<path d="M2583.6,507.7c-13.8-4.4-30.6-8.1-50.5-11.1c-15.1-2.7-26.1-5.2-32.9-7.6c-6.8-2.4-10.2-6.1-10.2-11.1s2.3-8.7,6.7-10.9 c4.4-2.2,11.5-3.3,21.3-3.3c11.6,0,24.3,2.4,38.1,7.2c13.9,4.8,26.2,11,36.9,18.4l32.4-58.2c-11.3-7.4-26.2-14.7-44.9-21.8 c-18.7-7.1-39.6-10.7-62.7-10.7c-33.7,0-60.2,7.6-79.3,22.7c-19.1,15.1-28.7,36.1-28.7,63.1c0,19,4.8,33.9,14.4,44.7 c9.6,10.8,21,18.5,34,22.9c13.1,4.5,28.9,8.3,47.6,11.6c14.6,2.7,25.1,5.3,31.6,7.8s9.8,6.5,9.8,11.8c0,10.4-9.7,15.6-29.3,15.6 c-13.7,0-28.5-2.3-44.7-6.9c-16.1-4.6-29.2-11.3-39.3-20.2l-33.3,60c9.2,7.4,24.6,14.7,46.2,22c21.7,7.3,45.2,10.9,70.7,10.9 c34.7,0,62.9-7.4,84.5-22.4c21.7-15,32.5-37.3,32.5-66.9c0-19.3-5-34.2-15.1-44.9S2597.4,512.1,2583.6,507.7z" transform="translate(0)"/>
<path d="M2883.4,575.3c0-19.3-5-34.2-15.1-44.9s-22-18.3-35.8-22.7c-13.8-4.4-30.6-8.1-50.5-11.1c-15.1-2.7-26.1-5.2-32.9-7.6 c-6.8-2.4-10.2-6.1-10.2-11.1s2.3-8.7,6.7-10.9c4.4-2.2,11.5-3.3,21.3-3.3c11.6,0,24.3,2.4,38.1,7.2c13.9,4.8,26.2,11,36.9,18.4 l32.4-58.2c-11.3-7.4-26.2-14.7-44.9-21.8c-18.7-7.1-39.6-10.7-62.7-10.7c-33.7,0-60.2,7.6-79.3,22.7 c-19.1,15.1-28.7,36.1-28.7,63.1c0,19,4.8,33.9,14.4,44.7c9.6,10.8,21,18.5,34,22.9c13.1,4.5,28.9,8.3,47.6,11.6 c14.6,2.7,25.1,5.3,31.6,7.8s9.8,6.5,9.8,11.8c0,10.4-9.7,15.6-29.3,15.6c-13.7,0-28.5-2.3-44.7-6.9c-16.1-4.6-29.2-11.3-39.3-20.2 l-33.3,60c9.2,7.4,24.6,14.7,46.2,22c21.7,7.3,45.2,10.9,70.7,10.9c34.7,0,62.9-7.4,84.5-22.4 C2872.6,627.2,2883.4,604.9,2883.4,575.3z" transform="translate(0)"/>
<rect x="2460.7" y="738.7" width="59.6" height="17.2" transform="translate(0)"/>
<path d="M2596.5,706.4c-5.7,0-11,1-15.8,3s-9,5-12.5,8.9v-9.4h-19.4v93.6h19.4v-52c0-8.6,2.1-15.3,6.3-20c4.2-4.7,9.5-7.1,15.9-7.1 c7.8,0,13.4,2.3,16.8,6.7c3.4,4.5,5.1,11.3,5.1,20.5v52h19.4v-56.8c0-12.8-3.2-22.6-9.5-29.3 C2615.8,709.8,2607.3,706.4,2596.5,706.4z" transform="translate(0)"/>
<path d="M2733.8,717.7c-3.6-3.4-7.9-6.1-13.1-8.2s-10.6-3.1-16.2-3.1c-8.7,0-16.5,2.1-23.5,6.3s-12.5,10-16.5,17.3 c-4,7.3-6,15.4-6,24.4c0,8.9,2,17.1,6,24.3c4,7.3,9.5,13,16.5,17.2s14.9,6.3,23.5,6.3c5.6,0,11-1,16.2-3.1 c5.1-2.1,9.5-4.8,13.1-8.2v24.4c0,8.5-2.5,14.8-7.6,18.7c-5,3.9-11,5.9-18,5.9c-6.7,0-12.4-1.6-17.3-4.7c-4.8-3.1-7.6-7.7-8.3-13.8 h-19.4c0.6,7.7,2.9,14.2,7.1,19.5s9.6,9.3,16.2,12c6.6,2.7,13.8,4,21.7,4c12.8,0,23.5-3.4,32-10.1c8.6-6.7,12.8-17.1,12.8-31.1 V708.9h-19.2V717.7z M2732.2,770.1c-2.5,4.7-6,8.3-10.4,11.2c-4.4,2.7-9.4,4-14.9,4c-5.7,0-10.8-1.4-15.2-4.3s-7.8-6.7-10.2-11.4 c-2.3-4.8-3.5-9.8-3.5-15.2c0-5.5,1.1-10.6,3.5-15.3s5.8-8.5,10.2-11.3s9.5-4.2,15.2-4.2c5.5,0,10.5,1.4,14.9,4s7.9,6.3,10.4,11 s3.8,10,3.8,15.8S2734.7,765.4,2732.2,770.1z" transform="translate(0)"/>
<polygon points="2867.9,708.9 2846.5,708.9 2820.9,741.9 2795.5,708.9 2773.1,708.9 2809.1,755 2771.5,802.5 2792.9,802.5 2820.1,767.9 2847.2,802.6 2869.6,802.6 2832,754.4 " transform="translate(0)"/>
<path d="M757.6,293.7c-20-10.8-42.6-16.2-67.8-16.2H600c-8.5,39.2-21.1,76.4-37.6,111.3c-9.9,20.8-21.1,40.6-33.6,59.4v207.2h88.9 V521.5h72c25.2,0,47.8-5.4,67.8-16.2s35.7-25.6,47.1-44.2c11.4-18.7,17.1-39.1,17.1-61.3c0.1-22.7-5.6-43.3-17-61.9 C793.3,319.2,777.6,304.5,757.6,293.7z M716.6,434.3c-9.3,8.9-21.6,13.3-36.7,13.3l-62.2,0.4v-92.5l62.2-0.4 c15.1,0,27.3,4.4,36.7,13.3c9.4,8.9,14,19.9,14,32.9C730.6,414.5,726,425.4,716.6,434.3z" transform="translate(0)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,36 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { LogoComponent } from './logo.component'
import { By } from '@angular/platform-browser'
describe('LogoComponent', () => {
let component: LogoComponent
let fixture: ComponentFixture<LogoComponent>
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [LogoComponent],
})
fixture = TestBed.createComponent(LogoComponent)
component = fixture.componentInstance
fixture.detectChanges()
})
it('should support extra classes', () => {
expect(fixture.debugElement.queryAll(By.css('.foo'))).toHaveLength(0)
component.extra_classes = 'foo'
fixture.detectChanges()
expect(fixture.debugElement.queryAll(By.css('.foo'))).toHaveLength(1)
})
it('should support setting height', () => {
expect(fixture.debugElement.query(By.css('svg')).attributes.height).toEqual(
'6em'
)
component.height = '10em'
fixture.detectChanges()
expect(fixture.debugElement.query(By.css('svg')).attributes.height).toEqual(
'10em'
)
})
})

View File

@@ -0,0 +1,18 @@
import { Component, Input } from '@angular/core'
@Component({
selector: 'app-logo',
templateUrl: './logo.component.html',
styleUrls: ['./logo.component.scss'],
})
export class LogoComponent {
@Input()
extra_classes: string
@Input()
height = '6em'
getClasses() {
return ['logo'].concat(this.extra_classes).join(' ')
}
}

View File

@@ -1,22 +1,5 @@
<app-page-header title="Dashboard" [subTitle]="subtitle" i18n-title>
<svg class="logo d-none d-md-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2897.4 896.6" height="6em">
<path class="leaf" d="M140,713.7c-3.4-16.4-10.3-49.1-11.2-49.1c-145.7-87.1-128.4-238-80.2-324.2C59,449,251.2,524,139.1,656.8 c-0.9,1.7,5.2,22.4,10.3,41.4c22.4-37.9,56-83.6,54.3-87.9C65.9,273.9,496.9,248.1,586.6,39.4c40.5,201.8-20.7,513.9-367.2,593.2 c-1.7,0.9-62.9,108.6-65.5,109.5c0-1.7-25.9-0.9-22.4-9.5C133.1,727.4,136.6,720.6,140,713.7L140,713.7z M135.7,632.6 c44-50.9-7.8-137.9-38.8-166.4C149.5,556.7,146,609.3,135.7,632.6L135.7,632.6z" transform="translate(0)" style="fill:#17541f"/>
<g class="text" style="fill:#000">
<path d="M1022.3,428.7c-17.8-19.9-42.7-29.8-74.7-29.8c-22.3,0-42.4,5.7-60.5,17.3c-18.1,11.6-32.3,27.5-42.5,47.8 s-15.3,42.9-15.3,67.8c0,24.9,5.1,47.5,15.3,67.8c10.3,20.3,24.4,36.2,42.5,47.8c18.1,11.5,38.3,17.3,60.5,17.3 c32,0,56.9-9.9,74.7-29.8v20.4v0.2h84.5V408.3h-84.5V428.7z M1010.5,575c-10.2,11.7-23.6,17.6-40.2,17.6s-29.9-5.9-40-17.6 s-15.1-26.1-15.1-43.3c0-17.1,5-31.6,15.1-43.3s23.4-17.6,40-17.6c16.6,0,30,5.9,40.2,17.6s15.3,26.1,15.3,43.3 S1020.7,563.3,1010.5,575z" transform="translate(0)"/>
<path d="M1381,416.1c-18.1-11.5-38.3-17.3-60.5-17.4c-32,0-56.9,9.9-74.7,29.8v-20.4h-84.5v390.7h84.5v-164 c17.8,19.9,42.7,29.8,74.7,29.8c22.3,0,42.4-5.7,60.5-17.3s32.3-27.5,42.5-47.8c10.2-20.3,15.3-42.9,15.3-67.8s-5.1-47.5-15.3-67.8 C1413.2,443.6,1399.1,427.7,1381,416.1z M1337.9,575c-10.1,11.7-23.4,17.6-40,17.6s-29.9-5.9-40-17.6s-15.1-26.1-15.1-43.3 c0-17.1,5-31.6,15.1-43.3s23.4-17.6,40-17.6s29.9,5.9,40,17.6s15.1,26.1,15.1,43.3S1347.9,563.3,1337.9,575z" transform="translate(0)"/>
<path d="M1672.2,416.8c-20.5-12-43-18-67.6-18c-24.9,0-47.6,5.9-68,17.6c-20.4,11.7-36.5,27.7-48.2,48s-17.6,42.7-17.6,67.3 c0.3,25.2,6.2,47.8,17.8,68c11.5,20.2,28,36,49.3,47.6c21.3,11.5,45.9,17.3,73.8,17.3c48.6,0,86.8-14.7,114.7-44l-52.5-48.9 c-8.6,8.3-17.6,14.6-26.7,19c-9.3,4.3-21.1,6.4-35.3,6.4c-11.6,0-22.5-3.6-32.7-10.9c-10.3-7.3-17.1-16.5-20.7-27.8h180l0.4-11.6 c0-29.6-6-55.7-18-78.2S1692.6,428.8,1672.2,416.8z M1558.3,503.2c2.1-12.1,7.5-21.8,16.2-29.1s18.7-10.9,30-10.9 s21.2,3.6,29.8,10.9c8.6,7.2,13.9,16.9,16,29.1H1558.3z" transform="translate(0)"/>
<path d="M1895.3,411.7c-11,5.6-20.3,13.7-28,24.4h-0.1v-28h-84.5v247.3h84.5V536.3c0-22.6,4.7-38.1,14.2-46.5 c9.5-8.5,22.7-12.7,39.6-12.7c6.2,0,13.5,1,21.8,3.1l10.7-72c-5.9-3.3-14.5-4.9-25.8-4.9C1917.1,403.3,1906.3,406.1,1895.3,411.7z" transform="translate(0)"/>
<rect x="1985" y="277.4" width="84.5" height="377.8" transform="translate(0)"/>
<path d="M2313.2,416.8c-20.5-12-43-18-67.6-18c-24.9,0-47.6,5.9-68,17.6s-36.5,27.7-48.2,48c-11.7,20.3-17.6,42.7-17.6,67.3 c0.3,25.2,6.2,47.8,17.8,68c11.5,20.2,28,36,49.3,47.6c21.3,11.5,45.9,17.3,73.8,17.3c48.6,0,86.8-14.7,114.7-44l-52.5-48.9 c-8.6,8.3-17.6,14.6-26.7,19c-9.3,4.3-21.1,6.4-35.3,6.4c-11.6,0-22.5-3.6-32.7-10.9c-10.3-7.3-17.1-16.5-20.7-27.8h180l0.4-11.6 c0-29.6-6-55.7-18-78.2S2333.6,428.8,2313.2,416.8z M2199.3,503.2c2.1-12.1,7.5-21.8,16.2-29.1s18.7-10.9,30-10.9 s21.2,3.6,29.8,10.9c8.6,7.2,13.9,16.9,16,29.1H2199.3z" transform="translate(0)"/>
<path d="M2583.6,507.7c-13.8-4.4-30.6-8.1-50.5-11.1c-15.1-2.7-26.1-5.2-32.9-7.6c-6.8-2.4-10.2-6.1-10.2-11.1s2.3-8.7,6.7-10.9 c4.4-2.2,11.5-3.3,21.3-3.3c11.6,0,24.3,2.4,38.1,7.2c13.9,4.8,26.2,11,36.9,18.4l32.4-58.2c-11.3-7.4-26.2-14.7-44.9-21.8 c-18.7-7.1-39.6-10.7-62.7-10.7c-33.7,0-60.2,7.6-79.3,22.7c-19.1,15.1-28.7,36.1-28.7,63.1c0,19,4.8,33.9,14.4,44.7 c9.6,10.8,21,18.5,34,22.9c13.1,4.5,28.9,8.3,47.6,11.6c14.6,2.7,25.1,5.3,31.6,7.8s9.8,6.5,9.8,11.8c0,10.4-9.7,15.6-29.3,15.6 c-13.7,0-28.5-2.3-44.7-6.9c-16.1-4.6-29.2-11.3-39.3-20.2l-33.3,60c9.2,7.4,24.6,14.7,46.2,22c21.7,7.3,45.2,10.9,70.7,10.9 c34.7,0,62.9-7.4,84.5-22.4c21.7-15,32.5-37.3,32.5-66.9c0-19.3-5-34.2-15.1-44.9S2597.4,512.1,2583.6,507.7z" transform="translate(0)"/>
<path d="M2883.4,575.3c0-19.3-5-34.2-15.1-44.9s-22-18.3-35.8-22.7c-13.8-4.4-30.6-8.1-50.5-11.1c-15.1-2.7-26.1-5.2-32.9-7.6 c-6.8-2.4-10.2-6.1-10.2-11.1s2.3-8.7,6.7-10.9c4.4-2.2,11.5-3.3,21.3-3.3c11.6,0,24.3,2.4,38.1,7.2c13.9,4.8,26.2,11,36.9,18.4 l32.4-58.2c-11.3-7.4-26.2-14.7-44.9-21.8c-18.7-7.1-39.6-10.7-62.7-10.7c-33.7,0-60.2,7.6-79.3,22.7 c-19.1,15.1-28.7,36.1-28.7,63.1c0,19,4.8,33.9,14.4,44.7c9.6,10.8,21,18.5,34,22.9c13.1,4.5,28.9,8.3,47.6,11.6 c14.6,2.7,25.1,5.3,31.6,7.8s9.8,6.5,9.8,11.8c0,10.4-9.7,15.6-29.3,15.6c-13.7,0-28.5-2.3-44.7-6.9c-16.1-4.6-29.2-11.3-39.3-20.2 l-33.3,60c9.2,7.4,24.6,14.7,46.2,22c21.7,7.3,45.2,10.9,70.7,10.9c34.7,0,62.9-7.4,84.5-22.4 C2872.6,627.2,2883.4,604.9,2883.4,575.3z" transform="translate(0)"/>
<rect x="2460.7" y="738.7" width="59.6" height="17.2" transform="translate(0)"/>
<path d="M2596.5,706.4c-5.7,0-11,1-15.8,3s-9,5-12.5,8.9v-9.4h-19.4v93.6h19.4v-52c0-8.6,2.1-15.3,6.3-20c4.2-4.7,9.5-7.1,15.9-7.1 c7.8,0,13.4,2.3,16.8,6.7c3.4,4.5,5.1,11.3,5.1,20.5v52h19.4v-56.8c0-12.8-3.2-22.6-9.5-29.3 C2615.8,709.8,2607.3,706.4,2596.5,706.4z" transform="translate(0)"/>
<path d="M2733.8,717.7c-3.6-3.4-7.9-6.1-13.1-8.2s-10.6-3.1-16.2-3.1c-8.7,0-16.5,2.1-23.5,6.3s-12.5,10-16.5,17.3 c-4,7.3-6,15.4-6,24.4c0,8.9,2,17.1,6,24.3c4,7.3,9.5,13,16.5,17.2s14.9,6.3,23.5,6.3c5.6,0,11-1,16.2-3.1 c5.1-2.1,9.5-4.8,13.1-8.2v24.4c0,8.5-2.5,14.8-7.6,18.7c-5,3.9-11,5.9-18,5.9c-6.7,0-12.4-1.6-17.3-4.7c-4.8-3.1-7.6-7.7-8.3-13.8 h-19.4c0.6,7.7,2.9,14.2,7.1,19.5s9.6,9.3,16.2,12c6.6,2.7,13.8,4,21.7,4c12.8,0,23.5-3.4,32-10.1c8.6-6.7,12.8-17.1,12.8-31.1 V708.9h-19.2V717.7z M2732.2,770.1c-2.5,4.7-6,8.3-10.4,11.2c-4.4,2.7-9.4,4-14.9,4c-5.7,0-10.8-1.4-15.2-4.3s-7.8-6.7-10.2-11.4 c-2.3-4.8-3.5-9.8-3.5-15.2c0-5.5,1.1-10.6,3.5-15.3s5.8-8.5,10.2-11.3s9.5-4.2,15.2-4.2c5.5,0,10.5,1.4,14.9,4s7.9,6.3,10.4,11 s3.8,10,3.8,15.8S2734.7,765.4,2732.2,770.1z" transform="translate(0)"/>
<polygon points="2867.9,708.9 2846.5,708.9 2820.9,741.9 2795.5,708.9 2773.1,708.9 2809.1,755 2771.5,802.5 2792.9,802.5 2820.1,767.9 2847.2,802.6 2869.6,802.6 2832,754.4 " transform="translate(0)"/>
<path d="M757.6,293.7c-20-10.8-42.6-16.2-67.8-16.2H600c-8.5,39.2-21.1,76.4-37.6,111.3c-9.9,20.8-21.1,40.6-33.6,59.4v207.2h88.9 V521.5h72c25.2,0,47.8-5.4,67.8-16.2s35.7-25.6,47.1-44.2c11.4-18.7,17.1-39.1,17.1-61.3c0.1-22.7-5.6-43.3-17-61.9 C793.3,319.2,777.6,304.5,757.6,293.7z M716.6,434.3c-9.3,8.9-21.6,13.3-36.7,13.3l-62.2,0.4v-92.5l62.2-0.4 c15.1,0,27.3,4.4,36.7,13.3c9.4,8.9,14,19.9,14,32.9C730.6,414.5,726,425.4,716.6,434.3z" transform="translate(0)"/>
</g>
</svg>
<app-logo extra_classes="d-none d-md-block"></app-logo>
</app-page-header>
<div class="row">

View File

@@ -16,6 +16,7 @@ import { IfPermissionsDirective } from 'src/app/directives/if-permissions.direct
import { NgxFileDropModule } from 'ngx-file-drop'
import { RouterTestingModule } from '@angular/router/testing'
import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap'
import { LogoComponent } from '../common/logo/logo.component'
describe('DashboardComponent', () => {
let component: DashboardComponent
@@ -33,6 +34,7 @@ describe('DashboardComponent', () => {
UploadFileWidgetComponent,
IfPermissionsDirective,
SavedViewWidgetComponent,
LogoComponent,
],
providers: [
PermissionsGuard,

View File

@@ -6,14 +6,33 @@
<table content class="table table-sm table-hover table-borderless mb-0">
<thead>
<tr>
<th i18n>Created</th>
<th scope="col" i18n>Created</th>
<th scope="col" i18n>Title</th>
</tr>
</thead>
<tbody *appIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }">
<tr *ngFor="let doc of documents">
<tr *ngFor="let doc of documents" (mouseleave)="mouseLeaveCard()">
<td><a routerLink="/documents/{{doc.id}}" class="d-block text-dark text-decoration-none">{{doc.created_date | customDate}}</a></td>
<td><a routerLink="/documents/{{doc.id}}" class="d-block text-dark text-decoration-none">{{doc.title | documentTitle}}<app-tag [tag]="t" *ngFor="let t of doc.tags$ | async" class="ms-1" (click)="clickTag(t, $event)"></app-tag></a></td>
<td class="position-relative">
<a routerLink="/documents/{{doc.id}}" title="Edit" i18n-title class="d-block text-dark text-decoration-none">{{doc.title | documentTitle}}<app-tag [tag]="t" *ngFor="let t of doc.tags$ | async" class="ms-1" (click)="clickTag(t, $event)"></app-tag></a>
<div class="btn-group position-absolute top-50 end-0 translate-middle-y">
<a [href]="getPreviewUrl(doc)" title="View Preview" i18n-title target="_blank" class="btn btn-sm px-4 py-0 btn-dark border-dark-subtle"
[ngbPopover]="previewContent" [popoverTitle]="doc.title | documentTitle"
autoClose="true" popoverClass="shadow popover-preview" container="body" (mouseenter)="mouseEnterPreview(doc)" (mouseleave)="mouseLeavePreview()" #popover="ngbPopover">
<svg class="buttonicon-xs" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#eye"/>
</svg>
</a>
<ng-template #previewContent>
<object [data]="getPreviewUrl(doc) | safeUrl" class="preview" width="100%"></object>
</ng-template>
<a [href]="getDownloadUrl(doc)" class="btn btn-sm px-4 py-0 btn-dark border-dark-subtle" title="Download" i18n-title (click)="$event.stopPropagation()">
<svg class="buttonicon-xs" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#download"/>
</svg>
</a>
</div>
</td>
</tr>
</tbody>
</table>

View File

@@ -10,3 +10,15 @@ th:first-child {
tbody app-tag {
cursor: pointer;
}
tr .btn-group {
margin-right: 2px;
box-shadow: -6px 0px 4px -1px rgba(var(--bs-body-bg-rgb), .5);
opacity: 0;
pointer-events: none;
}
tr:hover .btn-group {
opacity: 1;
pointer-events: all;
}

View File

@@ -1,6 +1,11 @@
import { DatePipe } from '@angular/common'
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import {
ComponentFixture,
TestBed,
fakeAsync,
tick,
} from '@angular/core/testing'
import { Router } from '@angular/router'
import { RouterTestingModule } from '@angular/router/testing'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
@@ -21,6 +26,8 @@ import { PermissionsService } from 'src/app/services/permissions.service'
import { DocumentService } from 'src/app/services/rest/document.service'
import { WidgetFrameComponent } from '../widget-frame/widget-frame.component'
import { SavedViewWidgetComponent } from './saved-view-widget.component'
import { By } from '@angular/platform-browser'
import { SafeUrlPipe } from 'src/app/pipes/safeurl.pipe'
const savedView: PaperlessSavedView = {
id: 1,
@@ -64,6 +71,7 @@ describe('SavedViewWidgetComponent', () => {
IfPermissionsDirective,
CustomDatePipe,
DocumentTitlePipe,
SafeUrlPipe,
],
providers: [
PermissionsGuard,
@@ -107,8 +115,39 @@ describe('SavedViewWidgetComponent', () => {
fixture.detectChanges()
expect(fixture.debugElement.nativeElement.textContent).toContain('doc2')
expect(fixture.debugElement.nativeElement.textContent).toContain('doc3')
// preview + download buttons
expect(
fixture.debugElement.queryAll(By.css('td a.btn'))[0].attributes['href']
).toEqual(component.getPreviewUrl(documentResults[0]))
expect(
fixture.debugElement.queryAll(By.css('td a.btn'))[1].attributes['href']
).toEqual(component.getDownloadUrl(documentResults[0]))
})
it('should show preview on mouseover after delay to preload content', fakeAsync(() => {
jest.spyOn(documentService, 'listFiltered').mockReturnValue(
of({
all: [2, 3],
count: 2,
results: documentResults,
})
)
component.ngOnInit()
fixture.detectChanges()
component.mouseEnterPreview(documentResults[0])
expect(component.popover.isOpen()).toBeTruthy()
expect(component.popoverHidden).toBeTruthy()
tick(600)
expect(component.popoverHidden).toBeFalsy()
component.mouseLeaveCard()
component.mouseEnterPreview(documentResults[1])
tick(100)
component.mouseLeavePreview()
tick(600)
expect(component.popover.isOpen()).toBeFalsy()
}))
it('should call api endpoint and load results', () => {
const listAllSpy = jest.spyOn(documentService, 'listFiltered')
listAllSpy.mockReturnValue(

View File

@@ -1,4 +1,12 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core'
import {
Component,
Input,
OnDestroy,
OnInit,
QueryList,
ViewChild,
ViewChildren,
} from '@angular/core'
import { Router } from '@angular/router'
import { Subscription } from 'rxjs'
import { PaperlessDocument } from 'src/app/data/paperless-document'
@@ -10,11 +18,15 @@ import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type'
import { OpenDocumentsService } from 'src/app/services/open-documents.service'
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
import { ComponentWithPermissions } from 'src/app/components/with-permissions/with-permissions.component'
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'
@Component({
selector: 'app-saved-view-widget',
templateUrl: './saved-view-widget.component.html',
styleUrls: ['./saved-view-widget.component.scss'],
styleUrls: [
'./saved-view-widget.component.scss',
'../../../document-list/popover-preview/popover-preview.scss',
],
})
export class SavedViewWidgetComponent
extends ComponentWithPermissions
@@ -39,6 +51,12 @@ export class SavedViewWidgetComponent
subscription: Subscription
@ViewChildren('popover') popovers: QueryList<NgbPopover>
popover: NgbPopover
mouseOnPreview = false
popoverHidden = true
ngOnInit(): void {
this.reload()
this.subscription = this.consumerStatusService
@@ -87,4 +105,38 @@ export class SavedViewWidgetComponent
{ rule_type: FILTER_HAS_TAGS_ALL, value: tag.id.toString() },
])
}
getPreviewUrl(document: PaperlessDocument): string {
return this.documentService.getPreviewUrl(document.id)
}
getDownloadUrl(document: PaperlessDocument): string {
return this.documentService.getDownloadUrl(document.id)
}
mouseEnterPreview(doc: PaperlessDocument) {
this.popover = this.popovers.get(this.documents.indexOf(doc))
this.mouseOnPreview = true
if (!this.popover.isOpen()) {
// we're going to open but hide to pre-load content during hover delay
this.popover.open()
this.popoverHidden = true
setTimeout(() => {
if (this.mouseOnPreview) {
// show popover
this.popoverHidden = false
} else {
this.popover.close()
}
}, 600)
}
}
mouseLeavePreview() {
this.mouseOnPreview = false
}
mouseLeaveCard() {
this.popover?.close()
}
}

View File

@@ -84,7 +84,7 @@ describe('UploadFileWidgetComponent', () => {
it('should change color by status phase', () => {
const processingStatus = new FileStatus()
processingStatus.phase = FileStatusPhase.PROCESSING
processingStatus.phase = FileStatusPhase.WORKING
expect(component.getStatusColor(processingStatus)).toEqual('primary')
const failedStatus = new FileStatus()
failedStatus.phase = FileStatusPhase.FAILED
@@ -134,7 +134,7 @@ function mockConsumerStatuses(consumerStatusService) {
switch (phase) {
case FileStatusPhase.FAILED:
return [new FileStatus()]
case FileStatusPhase.PROCESSING:
case FileStatusPhase.WORKING:
return [new FileStatus(), new FileStatus()]
case FileStatusPhase.STARTED:
return [new FileStatus(), new FileStatus(), new FileStatus()]

View File

@@ -90,8 +90,9 @@ export class UploadFileWidgetComponent extends ComponentWithPermissions {
getStatusColor(status: FileStatus) {
switch (status.phase) {
case FileStatusPhase.PROCESSING:
case FileStatusPhase.UPLOADING:
case FileStatusPhase.STARTED:
case FileStatusPhase.WORKING:
return 'primary'
case FileStatusPhase.FAILED:
return 'danger'

View File

@@ -53,6 +53,6 @@ describe('DocumentAsnComponent', () => {
.mockReturnValue(of(convertToParamMap({ id: '5578' })))
const navigateSpy = jest.spyOn(router, 'navigate')
component.ngOnInit()
expect(navigateSpy).toHaveBeenCalledWith(['404'])
expect(navigateSpy).toHaveBeenCalledWith(['404'], { replaceUrl: true })
})
})

View File

@@ -25,7 +25,9 @@ export class DocumentAsnComponent implements OnInit {
if (documentId.length == 1) {
this.router.navigate(['documents', documentId[0]])
} else {
this.router.navigate(['404'])
this.router.navigate(['404'], {
replaceUrl: true,
})
}
})
})

View File

@@ -174,7 +174,7 @@
<li [ngbNavItem]="DocumentDetailNavIDs.Notes" *ngIf="notesEnabled">
<a ngbNavLink i18n>Notes <span *ngIf="document?.notes.length" class="badge text-bg-secondary ms-1">{{document.notes.length}}</span></a>
<ng-template ngbNavContent>
<app-document-notes [documentId]="documentId" [notes]="document?.notes" (updated)="notesUpdated($event)"></app-document-notes>
<app-document-notes [documentId]="documentId" [notes]="document?.notes" [addDisabled]="!userCanEdit" (updated)="notesUpdated($event)"></app-document-notes>
</ng-template>
</li>

View File

@@ -23,7 +23,7 @@
}
::ng-deep .ng-select-taggable {
max-width: calc(100% - 46px); // fudge factor for ng-select button width
max-width: calc(100% - 90px); // fudge factor for (2x) ng-select button width
}
.btn-group .dropdown-toggle-split {

View File

@@ -355,14 +355,14 @@ describe('DocumentDetailComponent', () => {
.mockReturnValueOnce(throwError(() => new Error('unable to discard')))
component.discard()
fixture.detectChanges()
expect(navigateSpy).toHaveBeenCalledWith(['404'])
expect(navigateSpy).toHaveBeenCalledWith(['404'], { replaceUrl: true })
})
it('should 404 on invalid id', () => {
jest.spyOn(documentService, 'get').mockReturnValueOnce(of(null))
const navigateSpy = jest.spyOn(router, 'navigate')
fixture.detectChanges()
expect(navigateSpy).toHaveBeenCalledWith(['404'])
expect(navigateSpy).toHaveBeenCalledWith(['404'], { replaceUrl: true })
})
it('should support save, close and show success toast', () => {
@@ -668,7 +668,7 @@ describe('DocumentDetailComponent', () => {
const object = {
id: 22,
name: 'Correspondent22',
last_correspondence: new Date(),
last_correspondence: new Date().toISOString(),
} as PaperlessCorrespondent
const qfSpy = jest.spyOn(documentListViewService, 'quickFilter')
component.filterDocuments([object])

View File

@@ -213,22 +213,22 @@ export class DocumentDetailComponent
this.correspondentService
.listAll()
.pipe(first())
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.correspondents = result.results))
this.documentTypeService
.listAll()
.pipe(first())
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.documentTypes = result.results))
this.storagePathService
.listAll()
.pipe(first())
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.storagePaths = result.results))
this.userService
.listAll()
.pipe(first())
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.users = result.results))
this.route.paramMap
@@ -341,7 +341,9 @@ export class DocumentDetailComponent
this.openDocumentService.setDirty(doc, dirty)
},
error: (error) => {
this.router.navigate(['404'])
this.router.navigate(['404'], {
replaceUrl: true,
})
},
})
@@ -406,7 +408,7 @@ export class DocumentDetailComponent
) {
this.documentsService
.getSuggestions(doc.id)
.pipe(first())
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe({
next: (result) => {
this.suggestions = result
@@ -513,7 +515,9 @@ export class DocumentDetailComponent
this.openDocumentService.setDirty(doc, false)
},
error: () => {
this.router.navigate(['404'])
this.router.navigate(['404'], {
replaceUrl: true,
})
},
})
}

View File

@@ -50,7 +50,7 @@
</a>
<a class="btn btn-sm btn-outline-secondary" target="_blank" [href]="previewUrl"
[ngbPopover]="previewContent" [popoverTitle]="document.title | documentTitle"
autoClose="true" popoverClass="shadow" (mouseenter)="mouseEnterPreview()" (mouseleave)="mouseLeavePreview()" #popover="ngbPopover">
autoClose="true" popoverClass="shadow popover-preview" (mouseenter)="mouseEnterPreview()" (mouseleave)="mouseLeavePreview()" #popover="ngbPopover">
<svg class="sidebaricon" fill="currentColor" class="sidebaricon">
<use xlink:href="assets/bootstrap-icons.svg#eye"/>
</svg>&nbsp;<span class="d-none d-md-inline" i18n>View</span>
@@ -87,14 +87,14 @@
</svg>
<small>{{(document.storage_path$ | async)?.name}}</small>
</button>
<div *ngIf="document.archive_serial_number" class="list-group-item me-2 bg-light text-dark p-1 border-0">
<div *ngIf="document.archive_serial_number | isNumber" class="list-group-item me-2 bg-light text-dark p-1 border-0">
<svg class="metadata-icon me-2 text-muted" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#upc-scan"/>
</svg>
<small>#{{document.archive_serial_number}}</small>
</div>
<ng-template #dateTooltip>
<div class="d-flex flex-column">
<div class="d-flex flex-column text-light">
<span i18n>Created: {{ document.created | customDate }}</span>
<span i18n>Added: {{ document.added | customDate }}</span>
<span i18n>Modified: {{ document.modified | customDate }}</span>

View File

@@ -18,6 +18,7 @@ import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
import { SafeUrlPipe } from 'src/app/pipes/safeurl.pipe'
import { DocumentCardLargeComponent } from './document-card-large.component'
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
const doc = {
id: 10,
@@ -48,6 +49,7 @@ describe('DocumentCardLargeComponent', () => {
CustomDatePipe,
IfPermissionsDirective,
SafeUrlPipe,
IsNumberPipe,
],
providers: [DatePipe],
imports: [

View File

@@ -65,7 +65,7 @@
<small>{{document.created_date | customDate:'mediumDate'}}</small>
</div>
</div>
<div *ngIf="document.archive_serial_number" class="ps-0 p-1">
<div *ngIf="document.archive_serial_number | isNumber" class="ps-0 p-1">
<svg class="metadata-icon me-2 text-muted" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#upc-scan"/>
</svg>
@@ -87,7 +87,7 @@
</a>
<a [href]="previewUrl" target="_blank" class="btn btn-sm btn-outline-secondary"
[ngbPopover]="previewContent" [popoverTitle]="document.title | documentTitle"
autoClose="true" popoverClass="shadow" (mouseenter)="mouseEnterPreview()" (mouseleave)="mouseLeavePreview()" #popover="ngbPopover">
autoClose="true" popoverClass="shadow popover-preview" (mouseenter)="mouseEnterPreview()" (mouseleave)="mouseLeavePreview()" #popover="ngbPopover">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>

View File

@@ -21,6 +21,7 @@ import { of } from 'rxjs'
import { By } from '@angular/platform-browser'
import { TagComponent } from '../../common/tag/tag.component'
import { PaperlessTag } from 'src/app/data/paperless-tag'
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
const doc = {
id: 10,
@@ -62,6 +63,7 @@ describe('DocumentCardSmallComponent', () => {
IfPermissionsDirective,
SafeUrlPipe,
TagComponent,
IsNumberPipe,
],
providers: [DatePipe],
imports: [

View File

@@ -17,7 +17,6 @@ import {
NgbDropdownModule,
NgbModal,
NgbModalRef,
NgbPagination,
NgbPopoverModule,
NgbTooltipModule,
} from '@ng-bootstrap/ng-bootstrap'
@@ -63,6 +62,7 @@ import { HttpErrorResponse } from '@angular/common/http'
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
import { SettingsService } from 'src/app/services/settings.service'
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
const docs: PaperlessDocument[] = [
{
@@ -126,6 +126,7 @@ describe('DocumentListComponent', () => {
DocumentTitlePipe,
UsernamePipe,
SafeHtmlPipe,
IsNumberPipe,
],
providers: [
FilterPipe,
@@ -259,7 +260,7 @@ describe('DocumentListComponent', () => {
.mockReturnValue(of(convertToParamMap({ id: '10' })))
const navigateSpy = jest.spyOn(router, 'navigate')
fixture.detectChanges()
expect(navigateSpy).toHaveBeenCalledWith(['404'])
expect(navigateSpy).toHaveBeenCalledWith(['404'], { replaceUrl: true })
})
it('should load saved view from query params', () => {

View File

@@ -153,7 +153,9 @@ export class DocumentListComponent
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(({ view }) => {
if (!view) {
this.router.navigate(['404'])
this.router.navigate(['404'], {
replaceUrl: true,
})
return
}
this.unmodifiedSavedView = view

View File

@@ -1,90 +1,89 @@
<div class="row flex-wrap" tourAnchor="tour.documents-filter-editor">
<div class="col mb-3 mb-xxl-0">
<div class="form-inline d-flex align-items-center">
<div class="input-group input-group-sm flex-fill w-auto flex-nowrap">
<div ngbDropdown>
<button class="btn btn-sm btn-outline-primary" ngbDropdownToggle>{{textFilterTargetName}}</button>
<div class="dropdown-menu shadow" ngbDropdownMenu>
<button *ngFor="let t of textFilterTargets" ngbDropdownItem [class.active]="textFilterTarget === t.id" (click)="changeTextFilterTarget(t.id)">{{t.name}}</button>
</div>
<div class="row flex-wrap row-gap-3" tourAnchor="tour.documents-filter-editor">
<div class="col">
<div class="form-inline d-flex align-items-center">
<div class="input-group input-group-sm flex-fill w-auto flex-nowrap">
<div ngbDropdown>
<button class="btn btn-sm btn-outline-primary" ngbDropdownToggle>{{textFilterTargetName}}</button>
<div class="dropdown-menu shadow" ngbDropdownMenu>
<button *ngFor="let t of textFilterTargets" ngbDropdownItem [class.active]="textFilterTarget === t.id" (click)="changeTextFilterTarget(t.id)">{{t.name}}</button>
</div>
<select *ngIf="textFilterTarget === 'asn'" class="form-select flex-grow-0 w-auto" [(ngModel)]="textFilterModifier" (change)="textFilterModifierChange()">
<option *ngFor="let m of textFilterModifiers" ngbDropdownItem [value]="m.id">{{m.label}}</option>
</select>
<button *ngIf="_textFilter" class="btn btn-link btn-sm px-0 position-absolute top-0 end-0 z-10" (click)="resetTextField()">
<svg fill="currentColor" class="buttonicon-sm me-1">
<use xlink:href="assets/bootstrap-icons.svg#x"/>
</svg>
</button>
<input #textFilterInput class="form-control form-control-sm" type="text" [disabled]="textFilterModifierIsNull" [(ngModel)]="textFilter" (keyup)="textFilterKeyup($event)" [readonly]="textFilterTarget === 'fulltext-morelike'">
</div>
</div>
</div>
<select *ngIf="textFilterTarget === 'asn'" class="form-select flex-grow-0 w-auto" [(ngModel)]="textFilterModifier" (change)="textFilterModifierChange()">
<option *ngFor="let m of textFilterModifiers" ngbDropdownItem [value]="m.id">{{m.label}}</option>
</select>
<button *ngIf="_textFilter" class="btn btn-link btn-sm px-0 position-absolute top-0 end-0 z-10" (click)="resetTextField()">
<svg fill="currentColor" class="buttonicon-sm me-1">
<use xlink:href="assets/bootstrap-icons.svg#x"/>
</svg>
</button>
<input #textFilterInput class="form-control form-control-sm" type="text" [disabled]="textFilterModifierIsNull" [(ngModel)]="textFilter" (keyup)="textFilterKeyup($event)" [readonly]="textFilterTarget === 'fulltext-morelike'">
</div>
</div>
</div>
<div class="col-auto">
<div class="d-flex flex-wrap gap-3">
<div class="d-flex flex-wrap gap-2">
<app-filterable-dropdown class="flex-fill" title="Tags" icon="tag-fill" i18n-title
filterPlaceholder="Filter tags" i18n-filterPlaceholder
[items]="tags"
[manyToOne]="true"
[(selectionModel)]="tagSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onTagsDropdownOpen()"
[documentCounts]="tagDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
<app-filterable-dropdown class="flex-fill" title="Correspondent" icon="person-fill" i18n-title
filterPlaceholder="Filter correspondents" i18n-filterPlaceholder
[items]="correspondents"
[(selectionModel)]="correspondentSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onCorrespondentDropdownOpen()"
[documentCounts]="correspondentDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
<app-filterable-dropdown class="flex-fill" title="Document type" icon="file-earmark-fill" i18n-title
filterPlaceholder="Filter document types" i18n-filterPlaceholder
[items]="documentTypes"
[(selectionModel)]="documentTypeSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onDocumentTypeDropdownOpen()"
[documentCounts]="documentTypeDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
<app-filterable-dropdown class="flex-fill" title="Storage path" icon="folder-fill" i18n-title
filterPlaceholder="Filter storage paths" i18n-filterPlaceholder
[items]="storagePaths"
[(selectionModel)]="storagePathSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onStoragePathDropdownOpen()"
[documentCounts]="storagePathDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
</div>
<div class="d-flex flex-wrap gap-2">
<app-date-dropdown
title="Created" i18n-title
(datesSet)="updateRules()"
[(dateBefore)]="dateCreatedBefore"
[(dateAfter)]="dateCreatedAfter"
[(relativeDate)]="dateCreatedRelativeDate"></app-date-dropdown>
<app-date-dropdown
title="Added" i18n-title
(datesSet)="updateRules()"
[(dateBefore)]="dateAddedBefore"
[(dateAfter)]="dateAddedAfter"
[(relativeDate)]="dateAddedRelativeDate"></app-date-dropdown>
</div>
<div class="d-flex flex-wrap">
<app-permissions-filter-dropdown
title="Permissions" i18n-title
(ownerFilterSet)="updateRules()"
[(selectionModel)]="permissionsSelectionModel"></app-permissions-filter-dropdown>
</div>
<div class="d-flex flex-wrap d-none d-sm-inline-block">
<button class="btn btn-outline-secondary btn-sm" [disabled]="!rulesModified" (click)="resetSelected()">
<svg class="toolbaricon ms-n1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#x"></use>
</svg><ng-container i18n>Reset filters</ng-container>
</button>
</div>
</div>
</div>
<div class="w-100 d-xxl-none"></div>
<div class="col col-xl-auto">
<div class="d-flex flex-wrap gap-3">
<div class="d-flex flex-wrap gap-2">
<app-filterable-dropdown class="flex-fill" title="Tags" icon="tag-fill" i18n-title
filterPlaceholder="Filter tags" i18n-filterPlaceholder
[items]="tags"
[manyToOne]="true"
[(selectionModel)]="tagSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onTagsDropdownOpen()"
[documentCounts]="tagDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
<app-filterable-dropdown class="flex-fill" title="Correspondent" icon="person-fill" i18n-title
filterPlaceholder="Filter correspondents" i18n-filterPlaceholder
[items]="correspondents"
[(selectionModel)]="correspondentSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onCorrespondentDropdownOpen()"
[documentCounts]="correspondentDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
<app-filterable-dropdown class="flex-fill" title="Document type" icon="file-earmark-fill" i18n-title
filterPlaceholder="Filter document types" i18n-filterPlaceholder
[items]="documentTypes"
[(selectionModel)]="documentTypeSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onDocumentTypeDropdownOpen()"
[documentCounts]="documentTypeDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
<app-filterable-dropdown class="flex-fill" title="Storage path" icon="folder-fill" i18n-title
filterPlaceholder="Filter storage paths" i18n-filterPlaceholder
[items]="storagePaths"
[(selectionModel)]="storagePathSelectionModel"
(selectionModelChange)="updateRules()"
(opened)="onStoragePathDropdownOpen()"
[documentCounts]="storagePathDocumentCounts"
[allowSelectNone]="true"></app-filterable-dropdown>
</div>
<div class="d-flex flex-wrap gap-2">
<app-date-dropdown
title="Created" i18n-title
(datesSet)="updateRules()"
[(dateBefore)]="dateCreatedBefore"
[(dateAfter)]="dateCreatedAfter"
[(relativeDate)]="dateCreatedRelativeDate"></app-date-dropdown>
<app-date-dropdown
title="Added" i18n-title
(datesSet)="updateRules()"
[(dateBefore)]="dateAddedBefore"
[(dateAfter)]="dateAddedAfter"
[(relativeDate)]="dateAddedRelativeDate"></app-date-dropdown>
</div>
<div class="d-flex flex-wrap">
<app-permissions-filter-dropdown
title="Permissions" i18n-title
(ownerFilterSet)="updateRules()"
[(selectionModel)]="permissionsSelectionModel"></app-permissions-filter-dropdown>
</div>
<div class="d-flex flex-wrap d-none d-sm-inline-block">
<button class="btn btn-outline-secondary btn-sm" [disabled]="!rulesModified" (click)="resetSelected()">
<svg class="toolbaricon ms-n1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#x"></use>
</svg><ng-container i18n>Reset filters</ng-container>
</button>
</div>
</div>
</div>
</div>

View File

@@ -115,9 +115,9 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
case FILTER_CORRESPONDENT:
case FILTER_HAS_CORRESPONDENT_ANY:
if (rule.value) {
return $localize`Correspondent: ${
this.correspondents.find((c) => c.id == +rule.value)?.name
}`
return $localize`Correspondent: ${this.correspondents.find(
(c) => c.id == +rule.value
)?.name}`
} else {
return $localize`Without correspondent`
}
@@ -125,9 +125,9 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
case FILTER_DOCUMENT_TYPE:
case FILTER_HAS_DOCUMENT_TYPE_ANY:
if (rule.value) {
return $localize`Document type: ${
this.documentTypes.find((dt) => dt.id == +rule.value)?.name
}`
return $localize`Document type: ${this.documentTypes.find(
(dt) => dt.id == +rule.value
)?.name}`
} else {
return $localize`Without document type`
}
@@ -135,17 +135,16 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
case FILTER_STORAGE_PATH:
case FILTER_HAS_STORAGE_PATH_ANY:
if (rule.value) {
return $localize`Storage path: ${
this.storagePaths.find((sp) => sp.id == +rule.value)?.name
}`
return $localize`Storage path: ${this.storagePaths.find(
(sp) => sp.id == +rule.value
)?.name}`
} else {
return $localize`Without storage path`
}
case FILTER_HAS_TAGS_ALL:
return $localize`Tag: ${
this.tags.find((t) => t.id == +rule.value)?.name
}`
return $localize`Tag: ${this.tags.find((t) => t.id == +rule.value)
?.name}`
case FILTER_HAS_ANY_TAG:
if (rule.value == 'false') {

View File

@@ -1,4 +1,4 @@
::ng-deep app-document-list .popover {
::ng-deep .popover.popover-preview {
max-width: 40rem;
.preview {
@@ -16,7 +16,7 @@
}
}
::ng-deep .popover-hidden .popover {
::ng-deep .popover-hidden .popover {
opacity: 0;
pointer-events: none;
}

View File

@@ -8,7 +8,7 @@
</div>
<div class="form-group mt-2 d-flex justify-content-end align-items-center">
<div *ngIf="networkActive" class="spinner-border spinner-border-sm fw-normal me-auto" role="status"></div>
<button type="button" class="btn btn-primary btn-sm" [disabled]="networkActive" (click)="addNote()" i18n>Add note</button>
<button type="button" class="btn btn-primary btn-sm" [disabled]="networkActive || addDisabled" (click)="addNote()" i18n>Add note</button>
</div>
</form>
<hr>

View File

@@ -1,6 +1,5 @@
.card-body {
max-height: 12rem;
overflow: scroll;
white-space: pre-wrap;
}

View File

@@ -26,6 +26,9 @@ export class DocumentNotesComponent extends ComponentWithPermissions {
@Input()
notes: PaperlessDocumentNote[] = []
@Input()
addDisabled: boolean = false
@Output()
updated: EventEmitter<PaperlessDocumentNote[]> = new EventEmitter()
users: PaperlessUser[]
@@ -61,7 +64,9 @@ export class DocumentNotesComponent extends ComponentWithPermissions {
error: (e) => {
this.networkActive = false
this.toastService.showError(
$localize`Error saving note: ${e.toString()}`
$localize`Error saving note`,
10000,
JSON.stringify(e)
)
},
})

View File

@@ -31,8 +31,12 @@ describe('CorrespondentListComponent', () => {
ReactiveFormsModule,
],
}).compileComponents()
correspondentsService = TestBed.inject(CorrespondentService)
})
// Tests are included in management-list.compontent.spec.ts
it('should use correct delete message', () => {
jest.spyOn(correspondentsService, 'listFiltered').mockReturnValue(
of({
count: 3,
@@ -56,15 +60,30 @@ describe('CorrespondentListComponent', () => {
fixture = TestBed.createComponent(CorrespondentListComponent)
component = fixture.componentInstance
fixture.detectChanges()
})
// Tests are included in management-list.compontent.spec.ts
it('should use correct delete message', () => {
expect(
component.getDeleteMessage({ id: 1, name: 'Correspondent1' })
).toEqual(
'Do you really want to delete the correspondent "Correspondent1"?'
)
})
it('should support very old date strings', () => {
jest.spyOn(correspondentsService, 'listFiltered').mockReturnValue(
of({
count: 1,
all: [1],
results: [
{
id: 1,
name: 'Correspondent1',
last_correspondence: '1832-12-31T15:32:54-07:52:58',
},
],
})
)
fixture = TestBed.createComponent(CorrespondentListComponent)
component = fixture.componentInstance
fixture.detectChanges()
})
})

View File

@@ -44,7 +44,19 @@ export class CorrespondentListComponent extends ManagementListComponent<Paperles
key: 'last_correspondence',
name: $localize`Last used`,
valueFn: (c: PaperlessCorrespondent) => {
return this.datePipe.transform(c.last_correspondence)
if (c.last_correspondence) {
let date = new Date(c.last_correspondence)
if (date.toString() == 'Invalid Date') {
// very old date strings are unable to be parsed
date = new Date(
c.last_correspondence
?.toString()
.replace(/-(\d\d):\d\d:\d\d/gm, `-$1:00`)
)
}
return this.datePipe.transform(date)
}
return ''
},
},
]

View File

@@ -243,7 +243,7 @@
<ng-container *appIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailAccount }">
<h4>
<ng-container i18n>Mail accounts</ng-container>
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editMailAccount()">
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editMailAccount()" *appIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailAccount }">
<svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg>
@@ -262,12 +262,12 @@
<li *ngFor="let account of mailAccounts" class="list-group-item" [formGroupName]="account.id">
<div class="row">
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editMailAccount(account)">{{account.name}}</button></div>
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editMailAccount(account)" [disabled]="!permissionsService.currentUserCan(PermissionAction.Change, PermissionType.MailAccount)">{{account.name}}</button></div>
<div class="col d-flex align-items-center">{{account.imap_server}}</div>
<div class="col">
<div class="btn-group">
<button *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" class="btn btn-sm btn-primary" type="button" (click)="editMailAccount(account)" i18n>Edit</button>
<button *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailAccount(account)" i18n>Delete</button>
<button *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" [disabled]="!userCanEdit(account)" class="btn btn-sm btn-primary" type="button" (click)="editMailAccount(account)" i18n>Edit</button>
<button *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailAccount }" [disabled]="!userIsOwner(account)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailAccount(account)" i18n>Delete</button>
</div>
</div>
</div>
@@ -280,7 +280,7 @@
<ng-container *appIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailRule }">
<h4 class="mt-4">
<ng-container i18n>Mail rules</ng-container>
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editMailRule()">
<button type="button" class="btn btn-sm btn-primary ms-4" (click)="editMailRule()" *appIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailRule }">
<svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg>
@@ -299,12 +299,12 @@
<li *ngFor="let rule of mailRules" class="list-group-item" [formGroupName]="rule.id">
<div class="row">
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editMailRule(rule)">{{rule.name}}</button></div>
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editMailRule(rule)" [disabled]="!permissionsService.currentUserCan(PermissionAction.Change, PermissionType.MailRule)">{{rule.name}}</button></div>
<div class="col d-flex align-items-center">{{(mailAccountService.getCached(rule.account) | async)?.name}}</div>
<div class="col">
<div class="btn-group">
<button *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailRule }" class="btn btn-sm btn-primary" type="button" (click)="editMailRule(rule)" i18n>Edit</button>
<button *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailRule }" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailRule(rule)" i18n>Delete</button>
<button *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailRule }" [disabled]="!userCanEdit(rule)" class="btn btn-sm btn-primary" type="button" (click)="editMailRule(rule)" i18n>Edit</button>
<button *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailRule }" [disabled]="!userIsOwner(rule)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailRule(rule)" i18n>Delete</button>
</div>
</div>
</div>
@@ -323,7 +323,7 @@
</ng-template>
</li>
<li [ngbNavItem]="SettingsNavIDs.UsersGroups" *appIfPermissions="{ action: PermissionAction.Add, type: PermissionType.User }" (mouseover)="maybeInitializeTab(SettingsNavIDs.UsersGroups)" (focusin)="maybeInitializeTab(SettingsNavIDs.UsersGroups)">
<li [ngbNavItem]="SettingsNavIDs.UsersGroups" *appIfPermissions="{ action: PermissionAction.View, type: PermissionType.User }" (mouseover)="maybeInitializeTab(SettingsNavIDs.UsersGroups)" (focusin)="maybeInitializeTab(SettingsNavIDs.UsersGroups)">
<a ngbNavLink i18n>Users & Groups</a>
<ng-template ngbNavContent>
@@ -334,7 +334,7 @@
<svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg>
<ng-container i18n>Add User</ng-container>
<ng-container *appIfPermissions="{ action: PermissionAction.Add, type: PermissionType.User }" i18n>Add User</ng-container>
</button>
</h4>
<ul class="list-group" formGroupName="usersGroup">
@@ -350,13 +350,13 @@
<li *ngFor="let user of users" class="list-group-item" [formGroupName]="user.id">
<div class="row">
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editUser(user)">{{user.username}}</button></div>
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editUser(user)" [disabled]="!permissionsService.currentUserCan(PermissionAction.Change, PermissionType.User)">{{user.username}}</button></div>
<div class="col d-flex align-items-center">{{user.first_name}} {{user.last_name}}</div>
<div class="col d-flex align-items-center">{{user.groups?.map(getGroupName, this).join(', ')}}</div>
<div class="col">
<div class="btn-group">
<button class="btn btn-sm btn-primary" type="button" (click)="editUser(user)" i18n>Edit</button>
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteUser(user)" i18n>Delete</button>
<button class="btn btn-sm btn-primary" type="button" (click)="editUser(user)" *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.User }" i18n>Edit</button>
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteUser(user)" *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.User }" i18n>Delete</button>
</div>
</div>
</div>
@@ -369,7 +369,7 @@
<svg class="sidebaricon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
</svg>
<ng-container i18n>Add Group</ng-container>
<ng-container *appIfPermissions="{ action: PermissionAction.Add, type: PermissionType.Group }" i18n>Add Group</ng-container>
</button>
</h4>
<ul *ngIf="groups.length > 0" class="list-group" formGroupName="groupsGroup">
@@ -385,13 +385,13 @@
<li *ngFor="let group of groups" class="list-group-item" [formGroupName]="group.id">
<div class="row">
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editGroup(group)">{{group.name}}</button></div>
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editGroup(group)" [disabled]="!permissionsService.currentUserCan(PermissionAction.Change, PermissionType.Group)">{{group.name}}</button></div>
<div class="col"></div>
<div class="col"></div>
<div class="col">
<div class="btn-group">
<button class="btn btn-sm btn-primary" type="button" (click)="editGroup(group)" i18n>Edit</button>
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteGroup(group)" i18n>Delete</button>
<button class="btn btn-sm btn-primary" type="button" (click)="editGroup(group)" *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Group }" i18n>Edit</button>
<button class="btn btn-sm btn-outline-danger" type="button" (click)="deleteGroup(group)" *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Group }" i18n>Delete</button>
</div>
</div>
</div>

View File

@@ -15,6 +15,7 @@ import {
NgbModule,
NgbNavLink,
NgbModalRef,
NgbAlertModule,
} from '@ng-bootstrap/ng-bootstrap'
import { of, throwError } from 'rxjs'
import { routes } from 'src/app/app-routing.module'
@@ -42,14 +43,21 @@ import { CheckComponent } from '../../common/input/check/check.component'
import { ColorComponent } from '../../common/input/color/color.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { SettingsComponent } from './settings.component'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { SelectComponent } from '../../common/input/select/select.component'
import { TextComponent } from '../../common/input/text/text.component'
import { PasswordComponent } from '../../common/input/password/password.component'
import { NumberComponent } from '../../common/input/number/number.component'
import { TagsComponent } from '../../common/input/tags/tags.component'
import { NgSelectModule } from '@ng-select/ng-select'
const savedViews = [
{ id: 1, name: 'view1' },
{ id: 2, name: 'view2' },
]
const users = [
{ id: 1, username: 'user1' },
{ id: 2, username: 'user2' },
{ id: 1, username: 'user1', is_superuser: false },
{ id: 2, username: 'user2', is_superuser: false },
]
const groups = [
{ id: 1, name: 'group1' },
@@ -60,8 +68,8 @@ const mailAccounts = [
{ id: 2, name: 'account2' },
]
const mailRules = [
{ id: 1, name: 'rule1' },
{ id: 2, name: 'rule2' },
{ id: 1, name: 'rule1', owner: 1 },
{ id: 2, name: 'rule2', owner: 2 },
]
describe('SettingsComponent', () => {
@@ -75,6 +83,7 @@ describe('SettingsComponent', () => {
let viewportScroller: ViewportScroller
let toastService: ToastService
let userService: UserService
let permissionsService: PermissionsService
let groupService: GroupService
let mailAccountService: MailAccountService
let mailRuleService: MailRuleService
@@ -89,24 +98,24 @@ describe('SettingsComponent', () => {
ConfirmDialogComponent,
CheckComponent,
ColorComponent,
SafeHtmlPipe,
SelectComponent,
TextComponent,
PasswordComponent,
NumberComponent,
TagsComponent,
MailAccountEditDialogComponent,
MailRuleEditDialogComponent,
],
providers: [
{
provide: PermissionsService,
useValue: {
currentUserCan: () => true,
},
},
CustomDatePipe,
DatePipe,
PermissionsGuard,
],
providers: [CustomDatePipe, DatePipe, PermissionsGuard],
imports: [
NgbModule,
HttpClientTestingModule,
RouterTestingModule.withRoutes(routes),
FormsModule,
ReactiveFormsModule,
NgbAlertModule,
NgSelectModule,
],
}).compileComponents()
@@ -117,52 +126,74 @@ describe('SettingsComponent', () => {
toastService = TestBed.inject(ToastService)
settingsService = TestBed.inject(SettingsService)
userService = TestBed.inject(UserService)
jest.spyOn(userService, 'listAll').mockReturnValue(
of({
all: users.map((u) => u.id),
count: users.length,
results: users.concat([]),
})
)
permissionsService = TestBed.inject(PermissionsService)
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
jest
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
.mockReturnValue(true)
jest
.spyOn(permissionsService, 'currentUserOwnsObject')
.mockReturnValue(true)
groupService = TestBed.inject(GroupService)
jest.spyOn(groupService, 'listAll').mockReturnValue(
of({
all: groups.map((g) => g.id),
count: groups.length,
results: groups.concat([]),
})
)
savedViewService = TestBed.inject(SavedViewService)
jest.spyOn(savedViewService, 'listAll').mockReturnValue(
of({
all: savedViews.map((v) => v.id),
count: savedViews.length,
results: (savedViews as PaperlessSavedView[]).concat([]),
})
)
mailAccountService = TestBed.inject(MailAccountService)
jest.spyOn(mailAccountService, 'listAll').mockReturnValue(
of({
all: mailAccounts.map((a) => a.id),
count: mailAccounts.length,
results: (mailAccounts as PaperlessMailAccount[]).concat([]),
})
)
mailRuleService = TestBed.inject(MailRuleService)
jest.spyOn(mailRuleService, 'listAll').mockReturnValue(
of({
all: mailRules.map((r) => r.id),
count: mailRules.length,
results: (mailRules as PaperlessMailRule[]).concat([]),
})
)
})
function completeSetup(excludeService = null) {
if (excludeService !== userService) {
jest.spyOn(userService, 'listAll').mockReturnValue(
of({
all: users.map((u) => u.id),
count: users.length,
results: users.concat([]),
})
)
}
if (excludeService !== groupService) {
jest.spyOn(groupService, 'listAll').mockReturnValue(
of({
all: groups.map((g) => g.id),
count: groups.length,
results: groups.concat([]),
})
)
}
if (excludeService !== savedViewService) {
jest.spyOn(savedViewService, 'listAll').mockReturnValue(
of({
all: savedViews.map((v) => v.id),
count: savedViews.length,
results: (savedViews as PaperlessSavedView[]).concat([]),
})
)
}
if (excludeService !== mailAccountService) {
jest.spyOn(mailAccountService, 'listAll').mockReturnValue(
of({
all: mailAccounts.map((a) => a.id),
count: mailAccounts.length,
results: (mailAccounts as PaperlessMailAccount[]).concat([]),
})
)
}
if (excludeService !== mailRuleService) {
jest.spyOn(mailRuleService, 'listAll').mockReturnValue(
of({
all: mailRules.map((r) => r.id),
count: mailRules.length,
results: (mailRules as PaperlessMailRule[]).concat([]),
})
)
}
fixture = TestBed.createComponent(SettingsComponent)
component = fixture.componentInstance
fixture.detectChanges()
})
}
it('should support tabbed settings & change URL, prevent navigation if dirty confirmation rejected', () => {
completeSetup()
const navigateSpy = jest.spyOn(router, 'navigate')
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
tabButtons[1].nativeElement.dispatchEvent(new MouseEvent('click'))
@@ -188,6 +219,7 @@ describe('SettingsComponent', () => {
})
it('should support direct link to tab by URL, scroll if needed', () => {
completeSetup()
jest
.spyOn(activatedRoute, 'paramMap', 'get')
.mockReturnValue(of(convertToParamMap({ section: 'mail' })))
@@ -200,6 +232,7 @@ describe('SettingsComponent', () => {
})
it('should lazy load tab data', () => {
completeSetup()
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
expect(component.savedViews).toBeUndefined()
@@ -222,6 +255,7 @@ describe('SettingsComponent', () => {
})
it('should support save saved views, show error', () => {
completeSetup()
component.maybeInitializeTab(3) // SavedViews
const toastErrorSpy = jest.spyOn(toastService, 'showError')
@@ -249,6 +283,7 @@ describe('SettingsComponent', () => {
})
it('should support save local settings updating appearance settings and calling API, show error', () => {
completeSetup()
const toastErrorSpy = jest.spyOn(toastService, 'showError')
const toastSpy = jest.spyOn(toastService, 'show')
const storeSpy = jest.spyOn(settingsService, 'storeSettings')
@@ -276,6 +311,7 @@ describe('SettingsComponent', () => {
})
it('should offer reload if settings changes require', () => {
completeSetup()
let toast: Toast
toastService.getToasts().subscribe((t) => (toast = t[0]))
component.initialize(true) // reset
@@ -289,6 +325,7 @@ describe('SettingsComponent', () => {
})
it('should allow setting theme color, visually apply change immediately but not save', () => {
completeSetup()
const appearanceSpy = jest.spyOn(
settingsService,
'updateAppearanceSettings'
@@ -305,6 +342,7 @@ describe('SettingsComponent', () => {
})
it('should support delete saved view', () => {
completeSetup()
component.maybeInitializeTab(3) // SavedViews
const toastSpy = jest.spyOn(toastService, 'showInfo')
const deleteSpy = jest.spyOn(savedViewService, 'delete')
@@ -317,6 +355,7 @@ describe('SettingsComponent', () => {
})
it('should support edit / create user, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.editUser(users[0])
@@ -333,6 +372,7 @@ describe('SettingsComponent', () => {
})
it('should support delete user, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.deleteUser(users[0])
@@ -353,6 +393,7 @@ describe('SettingsComponent', () => {
})
it('should logout current user if password changed, after delay', fakeAsync(() => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.editUser(users[0])
@@ -372,6 +413,7 @@ describe('SettingsComponent', () => {
}))
it('should support edit / create group, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.editGroup(groups[0])
@@ -387,6 +429,7 @@ describe('SettingsComponent', () => {
})
it('should support delete group, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.deleteGroup(users[0])
@@ -407,12 +450,71 @@ describe('SettingsComponent', () => {
})
it('should get group name', () => {
completeSetup()
component.maybeInitializeTab(5) // UsersGroups
expect(component.getGroupName(1)).toEqual(groups[0].name)
expect(component.getGroupName(11)).toEqual('')
})
it('should show errors on load if load mailAccounts failure', () => {
const toastErrorSpy = jest.spyOn(toastService, 'showError')
jest
.spyOn(mailAccountService, 'listAll')
.mockImplementation(() =>
throwError(() => new Error('failed to load mail accounts'))
)
completeSetup(mailAccountService)
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
tabButtons[3].nativeElement.dispatchEvent(new MouseEvent('click')) // mail tab
fixture.detectChanges()
expect(toastErrorSpy).toBeCalled()
})
it('should show errors on load if load mailRules failure', () => {
const toastErrorSpy = jest.spyOn(toastService, 'showError')
jest
.spyOn(mailRuleService, 'listAll')
.mockImplementation(() =>
throwError(() => new Error('failed to load mail rules'))
)
completeSetup(mailRuleService)
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
tabButtons[3].nativeElement.dispatchEvent(new MouseEvent('click')) // mail tab
fixture.detectChanges()
// tabButtons[4].nativeElement.dispatchEvent(new MouseEvent('click'))
expect(toastErrorSpy).toBeCalled()
})
it('should show errors on load if load users failure', () => {
const toastErrorSpy = jest.spyOn(toastService, 'showError')
jest
.spyOn(userService, 'listAll')
.mockImplementation(() =>
throwError(() => new Error('failed to load users'))
)
completeSetup(userService)
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
tabButtons[4].nativeElement.dispatchEvent(new MouseEvent('click')) // users tab
fixture.detectChanges()
expect(toastErrorSpy).toBeCalled()
})
it('should show errors on load if load groups failure', () => {
const toastErrorSpy = jest.spyOn(toastService, 'showError')
jest
.spyOn(groupService, 'listAll')
.mockImplementation(() =>
throwError(() => new Error('failed to load groups'))
)
completeSetup(groupService)
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
tabButtons[4].nativeElement.dispatchEvent(new MouseEvent('click')) // users tab
fixture.detectChanges()
expect(toastErrorSpy).toBeCalled()
})
it('should support edit / create mail account, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.editMailAccount(mailAccounts[0] as PaperlessMailAccount)
@@ -428,6 +530,7 @@ describe('SettingsComponent', () => {
})
it('should support delete mail account, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.deleteMailAccount(mailAccounts[0] as PaperlessMailAccount)
@@ -448,6 +551,7 @@ describe('SettingsComponent', () => {
})
it('should support edit / create mail rule, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.editMailRule(mailRules[0] as PaperlessMailRule)
@@ -463,6 +567,7 @@ describe('SettingsComponent', () => {
})
it('should support delete mail rule, show error if needed', () => {
completeSetup()
let modal: NgbModalRef
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
component.deleteMailRule(mailRules[0] as PaperlessMailRule)

View File

@@ -45,6 +45,11 @@ import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
import { MailAccountEditDialogComponent } from '../../common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component'
import { MailRuleEditDialogComponent } from '../../common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component'
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
import { ObjectWithPermissions } from 'src/app/data/object-with-permissions'
import {
PermissionAction,
PermissionsService,
} from 'src/app/services/permissions.service'
enum SettingsNavIDs {
General = 1,
@@ -140,7 +145,8 @@ export class SettingsComponent
private usersService: UserService,
private groupsService: GroupService,
private router: Router,
private modalService: NgbModal
private modalService: NgbModal,
public permissionsService: PermissionsService
) {
super()
this.settings.settingsSaved.subscribe(() => {
@@ -253,25 +259,73 @@ export class SettingsComponent
navID == SettingsNavIDs.UsersGroups &&
(!this.users || !this.groups)
) {
this.usersService.listAll().subscribe((r) => {
this.users = r.results
this.groupsService.listAll().subscribe((r) => {
this.groups = r.results
this.initialize(false)
this.usersService
.listAll()
.pipe(first())
.subscribe({
next: (r) => {
this.users = r.results
this.groupsService
.listAll()
.pipe(first())
.subscribe({
next: (r) => {
this.groups = r.results
this.initialize(false)
},
error: (e) => {
this.toastService.showError(
$localize`Error retrieving groups`,
10000,
JSON.stringify(e)
)
},
})
},
error: (e) => {
this.toastService.showError(
$localize`Error retrieving users`,
10000,
JSON.stringify(e)
)
},
})
})
} else if (
navID == SettingsNavIDs.Mail &&
(!this.mailAccounts || !this.mailRules)
) {
this.mailAccountService.listAll().subscribe((r) => {
this.mailAccounts = r.results
this.mailAccountService
.listAll()
.pipe(first())
.subscribe({
next: (r) => {
this.mailAccounts = r.results
this.mailRuleService.listAll().subscribe((r) => {
this.mailRules = r.results
this.initialize(false)
this.mailRuleService
.listAll()
.pipe(first())
.subscribe({
next: (r) => {
this.mailRules = r.results
this.initialize(false)
},
error: (e) => {
this.toastService.showError(
$localize`Error retrieving mail rules`,
10000,
JSON.stringify(e)
)
},
})
},
error: (e) => {
this.toastService.showError(
$localize`Error retrieving mail accounts`,
10000,
JSON.stringify(e)
)
},
})
})
}
}
@@ -642,6 +696,17 @@ export class SettingsComponent
this.settingsForm.get('themeColor').patchValue('')
}
userCanEdit(obj: ObjectWithPermissions): boolean {
return this.permissionsService.currentUserHasObjectPermissions(
PermissionAction.Change,
obj
)
}
userIsOwner(obj: ObjectWithPermissions): boolean {
return this.permissionsService.currentUserOwnsObject(obj)
}
editUser(user: PaperlessUser) {
var modal = this.modalService.open(UserEditDialogComponent, {
backdrop: 'static',

View File

@@ -53,7 +53,7 @@
<label class="form-check-label" for="task{{task.id}}"></label>
</div>
</th>
<td class="overflow-auto">{{ task.task_file_name }}</td>
<td class="overflow-auto name-col">{{ task.task_file_name }}</td>
<td class="d-none d-lg-table-cell">{{ task.date_created | customDate:'short' }}</td>
<td class="d-none d-lg-table-cell" *ngIf="activeTab !== 'started' && activeTab !== 'queued'">
<div *ngIf="task.result?.length > 50" class="result" (click)="expandTask(task); $event.stopPropagation();"
@@ -100,7 +100,7 @@
</table>
<div class="pb-3 d-sm-flex justify-content-between align-items-center">
<div class="pb-2 pb-sm-0" i18n *ngIf="tasks.length > 0">{tasks.length, plural, =1 {One {{this.activeTab}} task} other {{{tasks.length || 0}} total {{this.activeTab}} tasks}}</div>
<div class="pb-2 pb-sm-0" i18n *ngIf="tasks.length > 0">{tasks.length, plural, =1 {One {{this.activeTabLocalized}} task} other {{{tasks.length || 0}} total {{this.activeTabLocalized}} tasks}}</div>
<ngb-pagination *ngIf="tasks.length > pageSize" [(page)]="page" [pageSize]="pageSize" [collectionSize]="tasks.length" maxSize="8" size="sm"></ngb-pagination>
</div>
</ng-template>

View File

@@ -20,3 +20,9 @@ pre {
width: 0.8rem;
height: 0.8rem;
}
@media (max-width: 575.98px) {
.name-col {
max-width: 150px;
}
}

View File

@@ -124,4 +124,17 @@ export class TasksComponent
duringTabChange(navID: number) {
this.page = 1
}
get activeTabLocalized(): string {
switch (this.activeTab) {
case 'queued':
return $localize`queued`
case 'started':
return $localize`started`
case 'completed':
return $localize`completed`
case 'failed':
return $localize`failed`
}
}
}

View File

@@ -1,8 +1,17 @@
<div class="jumbotron text-center">
<svg width="5em" height="7em" viewBox="0 0 16 16" class="bi bi-emoji-frown" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path fill-rule="evenodd" d="M4.285 12.433a.5.5 0 0 0 .683-.183A3.498 3.498 0 0 1 8 10.5c1.295 0 2.426.703 3.032 1.75a.5.5 0 0 0 .866-.5A4.498 4.498 0 0 0 8 9.5a4.5 4.5 0 0 0-3.898 2.25.5.5 0 0 0 .183.683z"/>
<path d="M7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
</svg>
<h1 i18n>404 Not Found</h1>
</div>
<div class="d-sm-flex flex-wrap p-2 align-items-center justify-content-center" style="height: 75vh;">
<div class="p-4 pt-0">
<h1 style="font-size: 10rem;" class="fw-bold">404</h1>
</div>
<div class="p-4 pt-0">
<h1 class="display-6" i18n>Not Found</h1>
<p>
<a class="btn btn-primary" routerLink="/dashboard">
<svg class="buttonicon me-1" fill="currentColor">
<use xlink:href="assets/bootstrap-icons.svg#house" />
</svg>
<ng-container i18n>Go to Dashboard</ng-container>
</a>
</p>
</div>
<app-logo extra_classes="p-3 position-absolute bottom-0 start-50 translate-middle"></app-logo>
</div>

View File

@@ -1,5 +1,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { NotFoundComponent } from './not-found.component'
import { By } from '@angular/platform-browser'
import { LogoComponent } from '../common/logo/logo.component'
describe('NotFoundComponent', () => {
let component: NotFoundComponent
@@ -7,7 +9,7 @@ describe('NotFoundComponent', () => {
beforeEach(async () => {
TestBed.configureTestingModule({
declarations: [NotFoundComponent],
declarations: [NotFoundComponent, LogoComponent],
}).compileComponents()
fixture = TestBed.createComponent(NotFoundComponent)
@@ -18,6 +20,7 @@ describe('NotFoundComponent', () => {
it('should create component', () => {
expect(component).toBeTruthy()
expect(fixture.nativeElement.textContent).toContain('404 Not Found')
expect(fixture.nativeElement.textContent).toContain('Not Found')
expect(fixture.debugElement.queryAll(By.css('a'))).toHaveLength(1)
})
})

View File

@@ -1,5 +1,5 @@
import { MatchingModel } from './matching-model'
export interface PaperlessCorrespondent extends MatchingModel {
last_correspondence?: Date
last_correspondence?: string // Date
}

View File

@@ -1,4 +1,4 @@
import { ObjectWithId } from './object-with-id'
import { ObjectWithPermissions } from './object-with-permissions'
export enum IMAPSecurity {
None = 1,
@@ -6,7 +6,7 @@ export enum IMAPSecurity {
STARTTLS = 3,
}
export interface PaperlessMailAccount extends ObjectWithId {
export interface PaperlessMailAccount extends ObjectWithPermissions {
name: string
imap_server: string

View File

@@ -1,4 +1,4 @@
import { ObjectWithId } from './object-with-id'
import { ObjectWithPermissions } from './object-with-permissions'
export enum MailFilterAttachmentType {
Attachments = 1,
@@ -31,7 +31,7 @@ export enum MailMetadataCorrespondentOption {
FromCustom = 4,
}
export interface PaperlessMailRule extends ObjectWithId {
export interface PaperlessMailRule extends ObjectWithPermissions {
name: string
account: number // PaperlessMailAccount.id

View File

@@ -6,4 +6,5 @@ export interface WebsocketConsumerStatusMessage {
status?: string
message?: string
document_id: number
owner_id?: number
}

Some files were not shown because too many files have changed in this diff Show More