Compare commits

..

117 Commits

Author SHA1 Message Date
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
bbd4659fbf Include global and object-level permissions in export / import
adds test for transaction
2023-06-23 23:33:36 -07:00
157 changed files with 22566 additions and 14504 deletions

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"

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"

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

@@ -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 \

View File

@@ -26,8 +26,6 @@ gunicorn = "*"
imap-tools = "*"
langdetect = "*"
pathvalidate = "*"
pillow = "*"
pikepdf = "*"
python-gnupg = "*"
python-dotenv = "*"
python-dateutil = "*"
@@ -36,7 +34,7 @@ python-ipware = "*"
psycopg2 = "*"
rapidfuzz = "*"
redis = {extras = ["hiredis"], version = "*"}
scikit-learn = "~=1.2"
scikit-learn = "~=1.3"
whitenoise = "~=6.3"
watchdog = "~=2.2"
whoosh="~=2.7"
@@ -64,9 +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"
httpx = "*"
pikepdf = "==7.2.0"
pillow = "==9.5.0"
[dev-packages]
# Linting

1901
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

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
@@ -470,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,69 @@ 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.
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" 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

@@ -1,5 +1,52 @@
# Changelog
## 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

View File

@@ -524,7 +524,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 +1095,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 +1160,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 +1244,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

@@ -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

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

@@ -34,6 +34,7 @@
"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",
@@ -159,7 +160,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)
})

View File

@@ -333,84 +333,84 @@
<source>The dashboard can be used to show saved views, such as an &apos;Inbox&apos;. Those settings are found under Settings &gt; Saved Views once you have created some.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">146</context>
</context-group>
</trans-unit>
<trans-unit id="9075755296812854717" datatype="html">
<source>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.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">155</context>
<context context-type="linenumber">153</context>
</context-group>
</trans-unit>
<trans-unit id="7495498057594070122" datatype="html">
<source>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.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">165</context>
<context context-type="linenumber">158</context>
</context-group>
</trans-unit>
<trans-unit id="1334220418719920556" datatype="html">
<source>The filtering tools allow you to quickly find documents using various searches, dates, tags, etc.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">165</context>
</context-group>
</trans-unit>
<trans-unit id="5427326625898532358" datatype="html">
<source>Any combination of filters can be saved as a &apos;view&apos; which can then be displayed on the dashboard and / or sidebar.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">189</context>
<context context-type="linenumber">171</context>
</context-group>
</trans-unit>
<trans-unit id="2804886236408698479" datatype="html">
<source>Tags, correspondents, document types and storage paths can all be managed using these pages. They can also be created from the document edit view.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">199</context>
<context context-type="linenumber">176</context>
</context-group>
</trans-unit>
<trans-unit id="4680387114119209483" datatype="html">
<source>File Tasks shows you documents that have been consumed, are waiting to be, or may have failed during the process.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">209</context>
<context context-type="linenumber">184</context>
</context-group>
</trans-unit>
<trans-unit id="8116994662047019809" datatype="html">
<source>Check out the settings for various tweaks to the web app, toggle settings for saved views or setup e-mail checking.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">219</context>
<context context-type="linenumber">192</context>
</context-group>
</trans-unit>
<trans-unit id="7172877665285340082" datatype="html">
<source>Thank you! 🙏</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">229</context>
<context context-type="linenumber">200</context>
</context-group>
</trans-unit>
<trans-unit id="7354947513482088740" datatype="html">
<source>There are &lt;em&gt;tons&lt;/em&gt; more features and info we didn&apos;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.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">231</context>
<context context-type="linenumber">202</context>
</context-group>
</trans-unit>
<trans-unit id="4270528545616947218" datatype="html">
<source>Lastly, on behalf of every contributor to this community-supported project, thank you for using Paperless-ngx!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">233</context>
<context context-type="linenumber">204</context>
</context-group>
</trans-unit>
<trans-unit id="5749300816154614125" datatype="html">
<source>Initiating upload...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">289</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit id="2173456130768795374" datatype="html">
@@ -723,7 +723,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">594</context>
<context context-type="linenumber">600</context>
</context-group>
</trans-unit>
<trans-unit id="2526035785704676448" datatype="html">
@@ -2013,6 +2013,10 @@
<context context-type="sourcefile">src/app/components/common/input/permissions/permissions-form/permissions-form.component.html</context>
<context context-type="linenumber">46</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context>
<context context-type="linenumber">17</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
<context context-type="linenumber">49</context>
@@ -2296,13 +2300,43 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">202</context>
<context context-type="linenumber">201</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
<context context-type="linenumber">20</context>
</context-group>
</trans-unit>
<trans-unit id="8911158217491828773" datatype="html">
<source>View Preview</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context>
<context context-type="linenumber">19</context>
</context-group>
</trans-unit>
<trans-unit id="3099741642167775297" datatype="html">
<source>Download</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html</context>
<context context-type="linenumber">29</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">19</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
<context context-type="linenumber">102</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
<context context-type="linenumber">64</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
<context context-type="linenumber">99</context>
</context-group>
</trans-unit>
<trans-unit id="1069523139277190436" datatype="html">
<source>Statistics</source>
<context-group purpose="location">
@@ -2482,25 +2516,6 @@
<context context-type="linenumber">5,6</context>
</context-group>
</trans-unit>
<trans-unit id="3099741642167775297" datatype="html">
<source>Download</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">19</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
<context context-type="linenumber">102</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
<context context-type="linenumber">64</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
<context context-type="linenumber">99</context>
</context-group>
</trans-unit>
<trans-unit id="8659635229098859487" datatype="html">
<source>Download original</source>
<context-group purpose="location">
@@ -2538,7 +2553,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">40</context>
<context context-type="linenumber">37</context>
</context-group>
</trans-unit>
<trans-unit id="4452427314943113135" datatype="html">
@@ -2898,19 +2913,19 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">694</context>
<context context-type="linenumber">711</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">754</context>
<context context-type="linenumber">771</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">821</context>
<context context-type="linenumber">838</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">884</context>
<context context-type="linenumber">901</context>
</context-group>
</trans-unit>
<trans-unit id="1181910457994920507" datatype="html">
@@ -2925,19 +2940,19 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">696</context>
<context context-type="linenumber">713</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">756</context>
<context context-type="linenumber">773</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">823</context>
<context context-type="linenumber">840</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">886</context>
<context context-type="linenumber">903</context>
</context-group>
</trans-unit>
<trans-unit id="5729001209753056399" datatype="html">
@@ -3296,7 +3311,7 @@
</context-group>
</trans-unit>
<trans-unit id="8778002102373462277" datatype="html">
<source><x id="INTERPOLATION" equiv-text="otes.length}}"/> Notes</source>
<source><x id="INTERPOLATION" equiv-text="ocument.notes.length}}"/> Notes</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
<context context-type="linenumber">74</context>
@@ -3495,11 +3510,11 @@
<source>ASN</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">136,135</context>
<context context-type="linenumber">135</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">207</context>
<context context-type="linenumber">206</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
@@ -3625,7 +3640,9 @@
</context-group>
</trans-unit>
<trans-unit id="5195932016807797291" datatype="html">
<source>Correspondent: <x id="PH" equiv-text="this.correspondents.find((c) =&gt; c.id == +rule.value)?.name"/></source>
<source>Correspondent: <x id="PH" equiv-text="this.correspondents.find(
(c) =&gt; c.id == +rule.value
)?.name"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">118,120</context>
@@ -3639,7 +3656,9 @@
</context-group>
</trans-unit>
<trans-unit id="317796810569008208" datatype="html">
<source>Document type: <x id="PH" equiv-text="this.documentTypes.find((dt) =&gt; dt.id == +rule.value)?.name"/></source>
<source>Document type: <x id="PH" equiv-text="this.documentTypes.find(
(dt) =&gt; dt.id == +rule.value
)?.name"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">128,130</context>
@@ -3653,7 +3672,9 @@
</context-group>
</trans-unit>
<trans-unit id="232202047340644471" datatype="html">
<source>Storage path: <x id="PH" equiv-text="this.storagePaths.find((sp) =&gt; sp.id == +rule.value)?.name"/></source>
<source>Storage path: <x id="PH" equiv-text="this.storagePaths.find(
(sp) =&gt; sp.id == +rule.value
)?.name"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">138,140</context>
@@ -3667,108 +3688,109 @@
</context-group>
</trans-unit>
<trans-unit id="8180755793012580465" datatype="html">
<source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)?.name"/></source>
<source>Tag: <x id="PH" equiv-text="this.tags.find((t) =&gt; t.id == +rule.value)
?.name"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">146,148</context>
<context context-type="linenumber">146,147</context>
</context-group>
</trans-unit>
<trans-unit id="6494566478302448576" datatype="html">
<source>Without any tag</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">152</context>
<context context-type="linenumber">151</context>
</context-group>
</trans-unit>
<trans-unit id="6523384805359286307" datatype="html">
<source>Title: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">156</context>
<context context-type="linenumber">155</context>
</context-group>
</trans-unit>
<trans-unit id="1872523635812236432" datatype="html">
<source>ASN: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">159</context>
<context context-type="linenumber">158</context>
</context-group>
</trans-unit>
<trans-unit id="102674688969746976" datatype="html">
<source>Owner: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">162</context>
<context context-type="linenumber">161</context>
</context-group>
</trans-unit>
<trans-unit id="3550877650686009106" datatype="html">
<source>Owner not in: <x id="PH" equiv-text="rule.value"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">165</context>
<context context-type="linenumber">164</context>
</context-group>
</trans-unit>
<trans-unit id="1082034558646673343" datatype="html">
<source>Without an owner</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">168</context>
<context context-type="linenumber">167</context>
</context-group>
</trans-unit>
<trans-unit id="3100631071441658964" datatype="html">
<source>Title &amp; content</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">205</context>
<context context-type="linenumber">204</context>
</context-group>
</trans-unit>
<trans-unit id="1010505078885609376" datatype="html">
<source>Advanced search</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">210</context>
<context context-type="linenumber">209</context>
</context-group>
</trans-unit>
<trans-unit id="2649431021108393503" datatype="html">
<source>More like</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">216</context>
<context context-type="linenumber">215</context>
</context-group>
</trans-unit>
<trans-unit id="3697582909018473071" datatype="html">
<source>equals</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">234</context>
</context-group>
</trans-unit>
<trans-unit id="5325481293405718739" datatype="html">
<source>is empty</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">239</context>
<context context-type="linenumber">238</context>
</context-group>
</trans-unit>
<trans-unit id="6166785695326182482" datatype="html">
<source>is not empty</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">243</context>
<context context-type="linenumber">242</context>
</context-group>
</trans-unit>
<trans-unit id="4686622206659266699" datatype="html">
<source>greater than</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">247</context>
<context context-type="linenumber">246</context>
</context-group>
</trans-unit>
<trans-unit id="8014012170270529279" datatype="html">
<source>less than</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
<context context-type="linenumber">251</context>
<context context-type="linenumber">250</context>
</context-group>
</trans-unit>
<trans-unit id="7210076240260527720" datatype="html">
@@ -3846,18 +3868,18 @@
<context context-type="linenumber">25</context>
</context-group>
</trans-unit>
<trans-unit id="207390237682956115" datatype="html">
<source>Error saving note: <x id="PH" equiv-text="e.toString()"/></source>
<trans-unit id="2054854290951060833" datatype="html">
<source>Error saving note</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.ts</context>
<context context-type="linenumber">64</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="5682285129543775369" datatype="html">
<source>Error deleting note: <x id="PH" equiv-text="e.toString()"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-notes/document-notes.component.ts</context>
<context context-type="linenumber">80</context>
<context context-type="linenumber">85</context>
</context-group>
</trans-unit>
<trans-unit id="6316128875819022658" datatype="html">
@@ -4261,11 +4283,11 @@
<source> Update checking works by pinging the public <x id="START_LINK" ctype="x-a" equiv-text="&lt;a href=&quot;https://api.github.com/repos/paperless-ngx/paperless-ngx/releases/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;"/>Github API<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/> for the latest release to determine whether a new version is available.<x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Actual updating of the app must still be performed manually. </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">140,142</context>
<context context-type="linenumber">139,142</context>
</context-group>
</trans-unit>
<trans-unit id="5489945693955857309" datatype="html">
<source><x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="No track"/>No tracking data is collected by the app in any way.<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/></source>
<source><x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="&gt;"/>No tracking data is collected by the app in any way.<x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">144,146</context>
@@ -4394,7 +4416,7 @@
<source>Mail</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context>
<context context-type="linenumber">240,239</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit id="8913167930428886792" datatype="html">
@@ -4471,231 +4493,231 @@
<source>Saved view &quot;<x id="PH" equiv-text="savedView.name"/>&quot; deleted.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">476</context>
<context context-type="linenumber">482</context>
</context-group>
</trans-unit>
<trans-unit id="3891152409365583719" datatype="html">
<source>Settings saved</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">578</context>
<context context-type="linenumber">584</context>
</context-group>
</trans-unit>
<trans-unit id="7217000812750597833" datatype="html">
<source>Settings were saved successfully.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">579</context>
<context context-type="linenumber">585</context>
</context-group>
</trans-unit>
<trans-unit id="525012668859298131" datatype="html">
<source>Settings were saved successfully. Reload is required to apply some changes.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">583</context>
<context context-type="linenumber">589</context>
</context-group>
</trans-unit>
<trans-unit id="8491974984518503778" datatype="html">
<source>Reload now</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">584</context>
<context context-type="linenumber">590</context>
</context-group>
</trans-unit>
<trans-unit id="6839066544204061364" datatype="html">
<source>Use system language</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">603</context>
<context context-type="linenumber">609</context>
</context-group>
</trans-unit>
<trans-unit id="7729897675462249787" datatype="html">
<source>Use date format of display language</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">610</context>
<context context-type="linenumber">616</context>
</context-group>
</trans-unit>
<trans-unit id="5260584511980773458" datatype="html">
<source>Error while storing settings on server.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">630</context>
<context context-type="linenumber">636</context>
</context-group>
</trans-unit>
<trans-unit id="4510369340305901516" datatype="html">
<source>Password has been changed, you will be logged out momentarily.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">662</context>
<context context-type="linenumber">679</context>
</context-group>
</trans-unit>
<trans-unit id="2753185112875184719" datatype="html">
<source>Saved user &quot;<x id="PH" equiv-text="newUser.username"/>&quot;.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">669</context>
<context context-type="linenumber">686</context>
</context-group>
</trans-unit>
<trans-unit id="3471101514724661554" datatype="html">
<source>Error saving user.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">681</context>
<context context-type="linenumber">698</context>
</context-group>
</trans-unit>
<trans-unit id="5565868288871970148" datatype="html">
<source>Confirm delete user account</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">692</context>
<context context-type="linenumber">709</context>
</context-group>
</trans-unit>
<trans-unit id="8133663925694885325" datatype="html">
<source>This operation will permanently delete this user account.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">693</context>
<context context-type="linenumber">710</context>
</context-group>
</trans-unit>
<trans-unit id="857903183180440990" datatype="html">
<source>Deleted user</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">702</context>
<context context-type="linenumber">719</context>
</context-group>
</trans-unit>
<trans-unit id="1942566571910298572" datatype="html">
<source>Error deleting user.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">710</context>
<context context-type="linenumber">727</context>
</context-group>
</trans-unit>
<trans-unit id="5766640174051730159" datatype="html">
<source>Saved group &quot;<x id="PH" equiv-text="newGroup.name"/>&quot;.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">731</context>
<context context-type="linenumber">748</context>
</context-group>
</trans-unit>
<trans-unit id="8382042988405122578" datatype="html">
<source>Error saving group.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">741</context>
<context context-type="linenumber">758</context>
</context-group>
</trans-unit>
<trans-unit id="6538873300613683004" datatype="html">
<source>Confirm delete user group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">752</context>
<context context-type="linenumber">769</context>
</context-group>
</trans-unit>
<trans-unit id="7710984639498518244" datatype="html">
<source>This operation will permanently delete this user group.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">753</context>
<context context-type="linenumber">770</context>
</context-group>
</trans-unit>
<trans-unit id="6834066329827670963" datatype="html">
<source>Deleted group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">762</context>
<context context-type="linenumber">779</context>
</context-group>
</trans-unit>
<trans-unit id="8850738980935204840" datatype="html">
<source>Error deleting group.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">770</context>
<context context-type="linenumber">787</context>
</context-group>
</trans-unit>
<trans-unit id="6327501535846658797" datatype="html">
<source>Saved account &quot;<x id="PH" equiv-text="newMailAccount.name"/>&quot;.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">796</context>
<context context-type="linenumber">813</context>
</context-group>
</trans-unit>
<trans-unit id="8067594003836508139" datatype="html">
<source>Error saving account.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">808</context>
<context context-type="linenumber">825</context>
</context-group>
</trans-unit>
<trans-unit id="5641934153807844674" datatype="html">
<source>Confirm delete mail account</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">819</context>
<context context-type="linenumber">836</context>
</context-group>
</trans-unit>
<trans-unit id="7176985344323395435" datatype="html">
<source>This operation will permanently delete this mail account.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">820</context>
<context context-type="linenumber">837</context>
</context-group>
</trans-unit>
<trans-unit id="4233826387148482123" datatype="html">
<source>Deleted mail account</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">829</context>
<context context-type="linenumber">846</context>
</context-group>
</trans-unit>
<trans-unit id="6202503362522392111" datatype="html">
<source>Error deleting mail account.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">838</context>
<context context-type="linenumber">855</context>
</context-group>
</trans-unit>
<trans-unit id="123368655395433699" datatype="html">
<source>Saved rule &quot;<x id="PH" equiv-text="newMailRule.name"/>&quot;.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">859</context>
<context context-type="linenumber">876</context>
</context-group>
</trans-unit>
<trans-unit id="8951124554918814321" datatype="html">
<source>Error saving rule.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">871</context>
<context context-type="linenumber">888</context>
</context-group>
</trans-unit>
<trans-unit id="3896080636020672118" datatype="html">
<source>Confirm delete mail rule</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">882</context>
<context context-type="linenumber">899</context>
</context-group>
</trans-unit>
<trans-unit id="2250372580580310337" datatype="html">
<source>This operation will permanently delete this mail rule.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">883</context>
<context context-type="linenumber">900</context>
</context-group>
</trans-unit>
<trans-unit id="9077981247971516916" datatype="html">
<source>Deleted mail rule</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">892</context>
<context context-type="linenumber">909</context>
</context-group>
</trans-unit>
<trans-unit id="2033194641751367552" datatype="html">
<source>Error deleting mail rule.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context>
<context context-type="linenumber">901</context>
<context context-type="linenumber">918</context>
</context-group>
</trans-unit>
<trans-unit id="5101757640976222639" datatype="html">
@@ -4853,6 +4875,34 @@
<context context-type="linenumber">63</context>
</context-group>
</trans-unit>
<trans-unit id="9011556615675272238" datatype="html">
<source>queued</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.ts</context>
<context context-type="linenumber">131</context>
</context-group>
</trans-unit>
<trans-unit id="6415892379431855826" datatype="html">
<source>started</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.ts</context>
<context context-type="linenumber">133</context>
</context-group>
</trans-unit>
<trans-unit id="7510279840486540181" datatype="html">
<source>completed</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.ts</context>
<context context-type="linenumber">135</context>
</context-group>
</trans-unit>
<trans-unit id="4083337005045748464" datatype="html">
<source>failed</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/tasks/tasks.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="181464970911903082" datatype="html">
<source>404 Not Found</source>
<context-group purpose="location">
@@ -4948,7 +4998,7 @@
<source>Warning: You have unsaved changes to your document(s).</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-doc.guard.ts</context>
<context context-type="linenumber">17</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="159901853873315050" datatype="html">
@@ -4959,7 +5009,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">32</context>
<context context-type="linenumber">29</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
@@ -4999,28 +5049,28 @@
<source>You have unsaved changes to the saved view</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">34</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="7282050913165342352" datatype="html">
<source>Are you sure you want to close this saved view?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="856284624775342512" datatype="html">
<source>Save and close</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-saved-view.guard.ts</context>
<context context-type="linenumber">42</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit id="8311312207500500516" datatype="html">
<source>You don&apos;t have permissions to do that</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/guards/permissions.guard.ts</context>
<context context-type="linenumber">35</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="7536524521722799066" datatype="html">
@@ -5055,28 +5105,28 @@
<source>Document already exists.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="6108404046106249255" datatype="html">
<source>Document with ASN already exists.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">16</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="148389968432135849" datatype="html">
<source>File not found.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">17</context>
<context context-type="linenumber">18</context>
</context-group>
</trans-unit>
<trans-unit id="1520671543092565667" datatype="html">
<source>Pre-consume script does not exist.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">18</context>
<context context-type="linenumber">19</context>
</context-group>
<note priority="1" from="description">Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation</note>
</trans-unit>
@@ -5084,7 +5134,7 @@
<source>Error while executing pre-consume script.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">19</context>
<context context-type="linenumber">20</context>
</context-group>
<note priority="1" from="description">Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation</note>
</trans-unit>
@@ -5092,7 +5142,7 @@
<source>Post-consume script does not exist.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">21</context>
</context-group>
<note priority="1" from="description">Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation</note>
</trans-unit>
@@ -5100,7 +5150,7 @@
<source>Error while executing post-consume script.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">21</context>
<context context-type="linenumber">22</context>
</context-group>
<note priority="1" from="description">Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation</note>
</trans-unit>
@@ -5108,49 +5158,49 @@
<source>Received new file.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">22</context>
<context context-type="linenumber">23</context>
</context-group>
</trans-unit>
<trans-unit id="7337565919209746135" datatype="html">
<source>File type not supported.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">23</context>
<context context-type="linenumber">24</context>
</context-group>
</trans-unit>
<trans-unit id="5002399167376099234" datatype="html">
<source>Processing document...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">24</context>
<context context-type="linenumber">25</context>
</context-group>
</trans-unit>
<trans-unit id="1085975194762600381" datatype="html">
<source>Generating thumbnail...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">25</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="3280851677698431426" datatype="html">
<source>Retrieving date from document...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">26</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="7162102384876037296" datatype="html">
<source>Saving document...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">27</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="4550450765009165976" datatype="html">
<source>Finished.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/consumer-status.service.ts</context>
<context context-type="linenumber">28</context>
<context context-type="linenumber">29</context>
</context-group>
</trans-unit>
<trans-unit id="5523607037798226031" datatype="html">
@@ -5336,67 +5386,74 @@
<context context-type="linenumber">271</context>
</context-group>
</trans-unit>
<trans-unit id="9102963095355753902" datatype="html">
<source>Slovak</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">277</context>
</context-group>
</trans-unit>
<trans-unit id="4287008301409320881" datatype="html">
<source>Slovenian</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">277</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="8608389829607915090" datatype="html">
<source>Serbian</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">283</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit id="499386805970351976" datatype="html">
<source>Swedish</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">289</context>
<context context-type="linenumber">295</context>
</context-group>
</trans-unit>
<trans-unit id="5682359291233237791" datatype="html">
<source>Turkish</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">295</context>
<context context-type="linenumber">301</context>
</context-group>
</trans-unit>
<trans-unit id="4689443708886954687" datatype="html">
<source>Chinese Simplified</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">301</context>
<context context-type="linenumber">307</context>
</context-group>
</trans-unit>
<trans-unit id="4912706592792948707" datatype="html">
<source>ISO 8601</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">318</context>
<context context-type="linenumber">324</context>
</context-group>
</trans-unit>
<trans-unit id="313643372755303297" datatype="html">
<source>Successfully completed one-time migratration of settings to the database!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">429</context>
<context context-type="linenumber">435</context>
</context-group>
</trans-unit>
<trans-unit id="5558341108007064934" datatype="html">
<source>Unable to migrate settings to the database, please try saving manually.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">430</context>
<context context-type="linenumber">436</context>
</context-group>
</trans-unit>
<trans-unit id="1168781785897678748" datatype="html">
<source>You can restart the tour from the settings page.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/services/settings.service.ts</context>
<context context-type="linenumber">504</context>
<context context-type="linenumber">510</context>
</context-group>
</trans-unit>
<trans-unit id="5037437391296624618" datatype="html">

8920
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",
"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,6 +25,7 @@ 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'
@@ -49,6 +50,7 @@ registerLocaleData(localePt, 'pt-BR')
registerLocaleData(localePt, 'pt-PT')
registerLocaleData(localeRo)
registerLocaleData(localeRu)
registerLocaleData(localeSk)
registerLocaleData(localeSl)
registerLocaleData(localeSr)
registerLocaleData(localeSv)
@@ -74,15 +76,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

@@ -110,6 +110,7 @@ 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'
@@ -134,6 +135,7 @@ registerLocaleData(localePt, 'pt-BR')
registerLocaleData(localePt, 'pt-PT')
registerLocaleData(localeRo)
registerLocaleData(localeRu)
registerLocaleData(localeSk)
registerLocaleData(localeSl)
registerLocaleData(localeSr)
registerLocaleData(localeSv)

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

@@ -26,7 +26,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)
}

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

@@ -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

@@ -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
@@ -406,7 +406,7 @@ export class DocumentDetailComponent
) {
this.documentsService
.getSuggestions(doc.id)
.pipe(first())
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe({
next: (result) => {
this.suggestions = result

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>
@@ -94,7 +94,7 @@
<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

@@ -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

@@ -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

@@ -266,8 +266,8 @@
<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>
@@ -303,8 +303,8 @@
<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>

View File

@@ -48,8 +48,8 @@ const savedViews = [
{ 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 +60,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 +75,7 @@ describe('SettingsComponent', () => {
let viewportScroller: ViewportScroller
let toastService: ToastService
let userService: UserService
let permissionsService: PermissionsService
let groupService: GroupService
let mailAccountService: MailAccountService
let mailRuleService: MailRuleService
@@ -90,17 +91,7 @@ describe('SettingsComponent', () => {
CheckComponent,
ColorComponent,
],
providers: [
{
provide: PermissionsService,
useValue: {
currentUserCan: () => true,
},
},
CustomDatePipe,
DatePipe,
PermissionsGuard,
],
providers: [CustomDatePipe, DatePipe, PermissionsGuard],
imports: [
NgbModule,
HttpClientTestingModule,
@@ -117,6 +108,14 @@ describe('SettingsComponent', () => {
toastService = TestBed.inject(ToastService)
settingsService = TestBed.inject(SettingsService)
userService = TestBed.inject(UserService)
permissionsService = TestBed.inject(PermissionsService)
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
jest
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
.mockReturnValue(true)
jest
.spyOn(permissionsService, 'currentUserOwnsObject')
.mockReturnValue(true)
jest.spyOn(userService, 'listAll').mockReturnValue(
of({
all: users.map((u) => u.id),

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,
private permissionsService: PermissionsService
) {
super()
this.settings.settingsSaved.subscribe(() => {
@@ -642,6 +648,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

@@ -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

@@ -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,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

@@ -1,4 +1,3 @@
import { CanDeactivate } from '@angular/router'
import { Injectable } from '@angular/core'
import { Observable } from 'rxjs'
@@ -7,7 +6,7 @@ export interface ComponentCanDeactivate {
}
@Injectable()
export class DirtyDocGuard implements CanDeactivate<ComponentCanDeactivate> {
export class DirtyDocGuard {
canDeactivate(
component: ComponentCanDeactivate
): boolean | Observable<boolean> {

View File

@@ -1,4 +1,3 @@
import { CanDeactivate } from '@angular/router'
import { Injectable } from '@angular/core'
import { first, Observable, Subject } from 'rxjs'
import { DocumentListComponent } from '../components/document-list/document-list.component'
@@ -8,9 +7,7 @@ import { SettingsService } from '../services/settings.service'
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
@Injectable()
export class DirtySavedViewGuard
implements CanDeactivate<DocumentListComponent>
{
export class DirtySavedViewGuard {
constructor(
private modalService: NgbModal,
private settings: SettingsService

View File

@@ -1,5 +1,4 @@
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
UrlTree,
@@ -11,7 +10,7 @@ import { ToastService } from '../services/toast.service'
import { TourService } from 'ngx-ui-tour-ng-bootstrap'
@Injectable()
export class PermissionsGuard implements CanActivate {
export class PermissionsGuard {
constructor(
private permissionsService: PermissionsService,
private router: Router,

View File

@@ -11,7 +11,10 @@ import { Meta } from '@angular/platform-browser'
@Injectable()
export class CsrfInterceptor implements HttpInterceptor {
constructor(private cookieService: CookieService, private meta: Meta) {}
constructor(
private cookieService: CookieService,
private meta: Meta
) {}
intercept(
request: HttpRequest<unknown>,

View File

@@ -60,10 +60,10 @@ describe('ConsumerStatusService', () => {
current_progress: 50,
max_progress: 100,
document_id: 12,
status: 'STARTING',
status: 'WORKING',
})
expect(status.getProgress()).toBeCloseTo(0.6) // 0.8 * 50/100
expect(status.getProgress()).toBeCloseTo(0.6) // (0.8 * 50/100) + .2
expect(consumerStatusService.getConsumerStatusNotCompleted()).toEqual([
status,
])
@@ -194,6 +194,7 @@ describe('ConsumerStatusService', () => {
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(1)
consumerStatusService.dismissCompleted()
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(0)
consumerStatusService.disconnect()
})
it('should support dismiss', () => {
@@ -238,17 +239,40 @@ describe('ConsumerStatusService', () => {
})
it('should notify of document created on status message without upload', () => {
let detected = false
consumerStatusService.onDocumentDetected().subscribe((filestatus) => {
expect(filestatus.phase).toEqual(FileStatusPhase.STARTED)
detected = true
})
consumerStatusService.connect()
server.send({
task_id: '1234',
filename: 'file.pdf',
current_progress: 0,
max_progress: 100,
message: 'new_file',
status: 'STARTED',
})
consumerStatusService.disconnect()
expect(detected).toBeTruthy()
})
it('should notify of document in progress without upload', () => {
consumerStatusService.connect()
server.send({
task_id: '1234',
filename: 'file.pdf',
current_progress: 50,
max_progress: 100,
document_id: 12,
status: 'STARTING',
docuement_id: 12,
status: 'WORKING',
})
consumerStatusService.disconnect()
expect(consumerStatusService.getConsumerStatusNotCompleted()).toHaveLength(
1
)
})
})

View File

@@ -3,10 +3,11 @@ import { Subject } from 'rxjs'
import { environment } from 'src/environments/environment'
import { WebsocketConsumerStatusMessage } from '../data/websocket-consumer-status-message'
// see ConsumerFilePhase in src/documents/consumer.py
export enum FileStatusPhase {
STARTED = 0,
UPLOADING = 1,
PROCESSING = 2,
WORKING = 2,
SUCCESS = 3,
FAILED = 4,
}
@@ -49,7 +50,7 @@ export class FileStatus {
return 0.0
case FileStatusPhase.UPLOADING:
return (this.currentPhaseProgress / this.currentPhaseMaxProgress) * 0.2
case FileStatusPhase.PROCESSING:
case FileStatusPhase.WORKING:
return (
(this.currentPhaseProgress / this.currentPhaseMaxProgress) * 0.8 + 0.2
)
@@ -150,7 +151,7 @@ export class ConsumerStatusService {
let created = statusMessageGet.created
status.updateProgress(
FileStatusPhase.PROCESSING,
FileStatusPhase.WORKING,
statusMessage.current_progress,
statusMessage.max_progress
)
@@ -164,16 +165,25 @@ export class ConsumerStatusService {
}
status.documentId = statusMessage.document_id
if (created && statusMessage.status == 'STARTING') {
this.documentDetectedSubject.next(status)
if (statusMessage.status in FileStatusPhase) {
status.phase = FileStatusPhase[statusMessage.status]
}
if (statusMessage.status == 'SUCCESS') {
status.phase = FileStatusPhase.SUCCESS
this.documentConsumptionFinishedSubject.next(status)
}
if (statusMessage.status == 'FAILED') {
status.phase = FileStatusPhase.FAILED
this.documentConsumptionFailedSubject.next(status)
switch (status.phase) {
case FileStatusPhase.STARTED:
if (created) this.documentDetectedSubject.next(status)
break
case FileStatusPhase.SUCCESS:
this.documentConsumptionFinishedSubject.next(status)
break
case FileStatusPhase.FAILED:
this.documentConsumptionFailedSubject.next(status)
break
default:
break
}
}
}

View File

@@ -276,9 +276,9 @@ export class DocumentListViewService {
errorMessage = Object.keys(error.error)
.map((fieldName) => {
const fieldError: Array<string> = error.error[fieldName]
return `${
DOCUMENT_SORT_FIELDS.find((f) => f.field == fieldName)?.name
}: ${fieldError[0]}`
return `${DOCUMENT_SORT_FIELDS.find(
(f) => f.field == fieldName
)?.name}: ${fieldError[0]}`
})
.join(', ')
} else {

View File

@@ -2,7 +2,7 @@ import { ObjectWithId } from 'src/app/data/object-with-id'
import { AbstractPaperlessService } from './abstract-paperless-service'
export abstract class AbstractNameFilterService<
T extends ObjectWithId
T extends ObjectWithId,
> extends AbstractPaperlessService<T> {
listFiltered(
page?: number,

View File

@@ -8,7 +8,10 @@ import { environment } from 'src/environments/environment'
export abstract class AbstractPaperlessService<T extends ObjectWithId> {
protected baseUrl: string = environment.apiBaseUrl
constructor(protected http: HttpClient, private resourceName: string) {}
constructor(
protected http: HttpClient,
private resourceName: string
) {}
protected getResourceUrl(id: number = null, action: string = null): string {
let url = `${this.baseUrl}${this.resourceName}/`

View File

@@ -9,7 +9,10 @@ import { AbstractNameFilterService } from './abstract-name-filter-service'
providedIn: 'root',
})
export class GroupService extends AbstractNameFilterService<PaperlessGroup> {
constructor(http: HttpClient, private permissionService: PermissionsService) {
constructor(
http: HttpClient,
private permissionService: PermissionsService
) {
super(http, 'groups')
}

View File

@@ -9,7 +9,10 @@ import { AbstractNameFilterService } from './abstract-name-filter-service'
providedIn: 'root',
})
export class UserService extends AbstractNameFilterService<PaperlessUser> {
constructor(http: HttpClient, private permissionService: PermissionsService) {
constructor(
http: HttpClient,
private permissionService: PermissionsService
) {
super(http, 'users')
}

View File

@@ -272,6 +272,12 @@ export class SettingsService {
englishName: 'Russian',
dateInputFormat: 'dd.mm.yyyy',
},
{
code: 'sk-sk',
name: $localize`Slovak`,
englishName: 'Slovak',
dateInputFormat: 'dd.mm.yyyy',
},
{
code: 'sl-si',
name: $localize`Slovenian`,

View File

@@ -5,7 +5,7 @@ export const environment = {
apiBaseUrl: document.baseURI + 'api/',
apiVersion: '3',
appTitle: 'Paperless-ngx',
version: '1.16.4',
version: '1.17.0',
webSocketHost: window.location.host,
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
webSocketBaseUrl: base_url.pathname + 'ws/',

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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