Compare commits

..

61 Commits

Author SHA1 Message Date
shamoon
3c75deed80
Add paperless_remote tests to testpaths 2025-07-08 14:19:45 -07:00
shamoon
d05343c927
Test fixes / coverage 2025-07-08 14:19:45 -07:00
shamoon
e7972b7eaf
Coverage 2025-07-08 14:19:45 -07:00
shamoon
75a091cc0d
Fix test 2025-07-08 14:19:44 -07:00
shamoon
dca74803fd
Use output_content_format poller.result to get clean content 2025-07-08 14:19:44 -07:00
shamoon
3cf3d868d0
Some docs 2025-07-08 14:19:43 -07:00
shamoon
bf4fc6604a
Test 2025-07-08 14:19:43 -07:00
shamoon
e8c1eb86fa
This actually works
[ci skip]
2025-07-08 14:19:43 -07:00
shamoon
c3dad3cf69
Basic parse 2025-07-08 14:19:42 -07:00
shamoon
811bd66088
Ok, restart implementing this with just azure
[ci skip]
2025-07-08 14:19:42 -07:00
GitHub Actions
feb320cae9 Auto translate strings 2025-07-08 21:14:57 +00:00
shamoon
9178af5fb2
Feature: add Vietnamese translation (#10352) 2025-07-08 14:13:20 -07:00
dependabot[bot]
850444c2fc
docker(deps): Bump astral-sh/uv (#10343)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.9-python3.12-bookworm-slim to 0.7.19-python3.12-bookworm-slim.
- [Release notes](https://github.com/astral-sh/uv/releases)
- [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/uv/compare/0.7.9...0.7.19)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.7.19-python3.12-bookworm-slim
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-08 12:26:24 -07:00
GitHub Actions
90baba2cec Auto translate strings 2025-07-08 16:31:30 +00:00
dependabot[bot]
9889c59d3d
Chore(deps): Bump the small-changes group across 1 directory with 7 updates (#10347)
* Chore(deps): Bump the small-changes group across 1 directory with 7 updates

Bumps the small-changes group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [concurrent-log-handler](https://github.com/Preston-Landers/concurrent-log-handler) | `0.9.26` | `0.9.28` |
| [dateparser](https://github.com/scrapinghub/dateparser) | `1.2.1` | `1.2.2` |
| [imap-tools](https://github.com/ikvk/imap_tools) | `1.10.0` | `1.11.0` |
| [ocrmypdf](https://github.com/ocrmypdf/OCRmyPDF) | `16.10.2` | `16.10.4` |
| [pathvalidate](https://github.com/thombashi/pathvalidate) | `3.2.3` | `3.3.1` |
| [python-dotenv](https://github.com/theskumar/python-dotenv) | `1.1.0` | `1.1.1` |
| [scikit-learn](https://github.com/scikit-learn/scikit-learn) | `1.6.1` | `1.7.0` |



Updates `concurrent-log-handler` from 0.9.26 to 0.9.28
- [Release notes](https://github.com/Preston-Landers/concurrent-log-handler/releases)
- [Changelog](https://github.com/Preston-Landers/concurrent-log-handler/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Preston-Landers/concurrent-log-handler/compare/0.9.26...0.9.28)

Updates `dateparser` from 1.2.1 to 1.2.2
- [Release notes](https://github.com/scrapinghub/dateparser/releases)
- [Changelog](https://github.com/scrapinghub/dateparser/blob/master/HISTORY.rst)
- [Commits](https://github.com/scrapinghub/dateparser/compare/v1.2.1...v1.2.2)

Updates `imap-tools` from 1.10.0 to 1.11.0
- [Release notes](https://github.com/ikvk/imap_tools/releases)
- [Changelog](https://github.com/ikvk/imap_tools/blob/master/docs/release_notes.rst)
- [Commits](https://github.com/ikvk/imap_tools/compare/v1.10.0...v1.11.0)

Updates `ocrmypdf` from 16.10.2 to 16.10.4
- [Release notes](https://github.com/ocrmypdf/OCRmyPDF/releases)
- [Changelog](https://github.com/ocrmypdf/OCRmyPDF/blob/main/docs/release_notes.md)
- [Commits](https://github.com/ocrmypdf/OCRmyPDF/compare/v16.10.2...v16.10.4)

Updates `pathvalidate` from 3.2.3 to 3.3.1
- [Release notes](https://github.com/thombashi/pathvalidate/releases)
- [Changelog](https://github.com/thombashi/pathvalidate/blob/master/CHANGELOG.md)
- [Commits](https://github.com/thombashi/pathvalidate/compare/v3.2.3...v3.3.1)

Updates `python-dotenv` from 1.1.0 to 1.1.1
- [Release notes](https://github.com/theskumar/python-dotenv/releases)
- [Changelog](https://github.com/theskumar/python-dotenv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/theskumar/python-dotenv/compare/v1.1.0...v1.1.1)

Updates `scikit-learn` from 1.6.1 to 1.7.0
- [Release notes](https://github.com/scikit-learn/scikit-learn/releases)
- [Commits](https://github.com/scikit-learn/scikit-learn/compare/1.6.1...1.7.0)

---
updated-dependencies:
- dependency-name: concurrent-log-handler
  dependency-version: 0.9.28
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: small-changes
- dependency-name: dateparser
  dependency-version: 1.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: small-changes
- dependency-name: imap-tools
  dependency-version: 1.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: small-changes
- dependency-name: ocrmypdf
  dependency-version: 16.10.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: small-changes
- dependency-name: pathvalidate
  dependency-version: 3.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: small-changes
- dependency-name: python-dotenv
  dependency-version: 1.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: small-changes
- dependency-name: scikit-learn
  dependency-version: 1.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: small-changes
...

Signed-off-by: dependabot[bot] <support@github.com>

* Removes the setup_logging_queues call which is no longer needed

* Renames the MailboxTLS

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Trenton Holmes <797416+stumpylog@users.noreply.github.com>
2025-07-08 09:29:47 -07:00
Trenton H
3d2a3ede71
Chore: Updates dependency groups (#10339) 2025-07-07 17:37:58 -07:00
shamoon
bc019fab96
Fix: default to empty permissions for group creation (#10337) 2025-07-07 07:21:27 -07:00
shamoon
1cd21d0f38
Fix check scheduled workflows docstring 2025-07-03 00:11:12 -07:00
Antoine Mérino
f940ed0b7b
Fix: Fallback to Redis URL if no DB read cache Redis URL provided (#10315)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-07-02 10:59:24 -07:00
dependabot[bot]
3180ccf4cb
Chore(deps): Bump stefanzweifel/git-auto-commit-action (#10302)
Bumps the actions group with 1 update: [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action).


Updates `stefanzweifel/git-auto-commit-action` from 5 to 6
- [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases)
- [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: stefanzweifel/git-auto-commit-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 14:26:07 +00:00
dependabot[bot]
43abb0541b
Chore(deps-dev): Bump the frontend-eslint-dependencies group across 1 directory with 4 updates (#10311)
Bumps the frontend-eslint-dependencies group with 4 updates in the /src-ui directory: [@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), [@typescript-eslint/utils](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/utils) and [eslint](https://github.com/eslint/eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.35.0 to 8.35.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/v8.35.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.35.0 to 8.35.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/v8.35.1/packages/parser)

Updates `@typescript-eslint/utils` from 8.35.0 to 8.35.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/utils/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.35.1/packages/utils)

Updates `eslint` from 9.28.0 to 9.30.1
- [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/v9.28.0...v9.30.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 22:14:01 +00:00
dependabot[bot]
a3a405354f
Chore(deps-dev): Bump @types/node from 22.15.29 to 24.0.10 in /src-ui (#10306)
---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.0.10
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 22:03:30 +00:00
dependabot[bot]
09e98d600e
Chore(deps): Bump bootstrap from 5.3.6 to 5.3.7 in /src-ui (#10308)
---
updated-dependencies:
- dependency-name: bootstrap
  dependency-version: 5.3.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 21:52:26 +00:00
dependabot[bot]
01a39b9bb4
Chore(deps-dev): Bump webpack from 5.98.0 to 5.99.9 in /src-ui (#10309)
---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.99.9
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 21:39:13 +00:00
dependabot[bot]
3b0b40f071
Chore(deps-dev): Bump @playwright/test from 1.51.1 to 1.53.2 in /src-ui (#10307)
---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-version: 1.53.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 21:19:26 +00:00
GitHub Actions
6dce83865f Auto translate strings 2025-07-01 20:47:25 +00:00
dependabot[bot]
18252a19d7
Chore(deps): Bump the frontend-angular-dependencies group (#10303)
Bumps the frontend-angular-dependencies group in /src-ui with 13 updates:

| Package | From | To |
| --- | --- | --- |
| [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | `20.0.5` | `20.0.6` |
| [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | `20.0.5` | `20.0.6` |
| [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | `20.0.5` | `20.0.6` |
| [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) | `20.0.5` | `20.0.6` |
| [@angular/localize](https://github.com/angular/angular) | `20.0.5` | `20.0.6` |
| [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | `20.0.5` | `20.0.6` |
| [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) | `20.0.5` | `20.0.6` |
| [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | `20.0.5` | `20.0.6` |
| [@ng-bootstrap/ng-bootstrap](https://github.com/ng-bootstrap/ng-bootstrap) | `19.0.0` | `19.0.1` |
| [@ng-select/ng-select](https://github.com/ng-select/ng-select) | `15.1.2` | `15.1.3` |
| [ngx-cookie-service](https://github.com/stevermeister/ngx-cookie-service) | `19.1.2` | `20.0.1` |
| [ngx-device-detector](https://github.com/AhsanAyaz/ngx-device-detector) | `9.0.0` | `10.0.2` |
| [@angular/compiler-cli](https://github.com/angular/angular/tree/HEAD/packages/compiler-cli) | `20.0.5` | `20.0.6` |


Updates `@angular/common` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/common)

Updates `@angular/compiler` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/compiler)

Updates `@angular/core` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/core)

Updates `@angular/forms` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/forms)

Updates `@angular/localize` from 20.0.5 to 20.0.6
- [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/20.0.5...20.0.6)

Updates `@angular/platform-browser` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/platform-browser)

Updates `@angular/platform-browser-dynamic` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/platform-browser-dynamic)

Updates `@angular/router` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/router)

Updates `@ng-bootstrap/ng-bootstrap` from 19.0.0 to 19.0.1
- [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/19.0.0...19.0.1)

Updates `@ng-select/ng-select` from 15.1.2 to 15.1.3
- [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/v15.1.2...v15.1.3)

Updates `ngx-cookie-service` from 19.1.2 to 20.0.1
- [Release notes](https://github.com/stevermeister/ngx-cookie-service/releases)
- [Changelog](https://github.com/stevermeister/ngx-cookie-service/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stevermeister/ngx-cookie-service/compare/v19.1.2...v20.0.1)

Updates `ngx-device-detector` from 9.0.0 to 10.0.2
- [Release notes](https://github.com/AhsanAyaz/ngx-device-detector/releases)
- [Changelog](https://github.com/AhsanAyaz/ngx-device-detector/blob/master/steps-to-release.md)
- [Commits](https://github.com/AhsanAyaz/ngx-device-detector/compare/v9.0.0...v10.0.2)

Updates `@angular/compiler-cli` from 20.0.5 to 20.0.6
- [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/20.0.6/packages/compiler-cli)

---
updated-dependencies:
- dependency-name: "@angular/common"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/compiler"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/core"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/forms"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/localize"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser-dynamic"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/router"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@ng-bootstrap/ng-bootstrap"
  dependency-version: 19.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@ng-select/ng-select"
  dependency-version: 15.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: ngx-cookie-service
  dependency-version: 20.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: frontend-angular-dependencies
- dependency-name: ngx-device-detector
  dependency-version: 10.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/compiler-cli"
  dependency-version: 20.0.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 13:44:44 -07:00
Antoine Mérino
733a9674d6
Fix: prevent duplicate cachalot app in Django settings (#10300)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-07-01 09:11:58 -07:00
GitHub Actions
f3b6e15321 Auto translate strings 2025-07-01 05:59:21 +00:00
Antoine Mérino
6591d5da63
Performance: Add support for configuring date parser languages (#10181)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-07-01 05:57:38 +00:00
GitHub Actions
c974dc9400 Auto translate strings 2025-07-01 05:41:44 +00:00
Antoine Mérino
1671d49d44
Enhancement: Add a database caching for improved performance (#9784)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-06-30 22:36:24 -07:00
GitHub Actions
6b248ef140 Auto translate strings 2025-06-29 04:40:53 +00:00
shamoon
735681d294
Fix: correct api created coercion with timezone (#10287) 2025-06-28 21:39:14 -07:00
shamoon
a9085c65c5
Chore: fix some test warnings / errors 2025-06-27 15:03:10 -07:00
shamoon
e312425b1c
Fix: reset search query for preview on reset filter (#10279) 2025-06-27 14:36:38 -07:00
GitHub Actions
13fe064f6e Auto translate strings 2025-06-27 21:08:27 +00:00
shamoon
958f98d7e5
Chore: update to Angular 20 (#10273) 2025-06-27 14:06:40 -07:00
shamoon
dfad3c4d8e
Chore: clarify file deletion logging 2025-06-27 13:34:44 -07:00
shamoon
37267f3f04
Chore: add webpack directly 2025-06-22 20:03:48 -07:00
shamoon
b34538d991
Update support.yml 2025-06-22 08:03:41 -07:00
shamoon
fc97bd1315
Chore: create support discussion template 2025-06-22 08:02:26 -07:00
shamoon
dbf3721ec2
Chore: reject absurd max age values (#10243) 2025-06-22 07:39:36 -07:00
shamoon
59afbe09b1
Chore: remove PAPERLESS_DEBUG references to avoid confusion 2025-06-20 20:46:11 -07:00
shamoon
bfeaa1b119
Chore: update settings to pathlib 2025-06-20 10:50:44 -07:00
github-actions[bot]
e1c3124698
Changelog v2.17.1 - GHA (#10229) 2025-06-19 12:40:37 -07:00
shamoon
f2e22e103b
Bump version to 2.17.1 2025-06-19 12:07:49 -07:00
github-actions[bot]
dda94f013e
New Crowdin translations by GitHub Action (#10228)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-06-19 12:06:52 -07:00
GitHub Actions
caf00e7ead Auto translate strings 2025-06-19 18:52:01 +00:00
shamoon
f214440d2e
Fix: correct PAPERLESS_EMPTY_TRASH_DIR to Path (#10227) 2025-06-19 11:50:23 -07:00
github-actions[bot]
240c9ac511
Changelog v2.17.0 - GHA (#10225) 2025-06-19 10:43:13 -07:00
shamoon
a2c9bc346a
Bump version to 2.17.0 2025-06-19 10:12:41 -07:00
github-actions[bot]
b1cbb1c73a
New Crowdin translations by GitHub Action (#10131)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-06-19 09:32:51 -07:00
shamoon
434b1e3245
Fix: replace strtobool 2025-06-19 09:02:10 -07:00
GitHub Actions
497fdcaf4e Auto translate strings 2025-06-19 15:31:10 +00:00
shamoon
52b95f2b62
QoL: log version at startup, show backend vs frontend mismatch in system status (#10214) 2025-06-19 08:29:34 -07:00
shamoon
83391af866
Fix: more api fixes (#10204) 2025-06-19 08:28:41 -07:00
GitHub Actions
0a1786f39b Auto translate strings 2025-06-19 14:50:29 +00:00
shamoon
3b069ac034
Fix: restore expected pre-2.16 scheduled workflow offset behavior (#10218) 2025-06-19 14:47:54 +00:00
Sebastian Steinbeißer
07882b918b
Chore: switch from os.path to pathlib.Path (#9933)
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-06-18 17:16:59 +00:00
shamoon
cc5ba71f06
Chore: remove spaces from run log 2025-06-17 16:02:45 -07:00
299 changed files with 13053 additions and 11343 deletions

View File

@ -20,7 +20,6 @@
#
# This file is intended only to be used through VSCOde devcontainers. See README.md
# in the folder .devcontainer.
services:
broker:
image: docker.io/library/redis:7

55
.github/DISCUSSION_TEMPLATE/support.yml vendored Normal file
View File

@ -0,0 +1,55 @@
title: "[Support] "
body:
- type: textarea
id: description
attributes:
label: What's your question or issue?
description: Provide a clear and concise description of what you're trying to do, and what's going wrong.
placeholder: |
I'm trying to...
[Include screenshots if helpful]
validations:
required: true
- type: textarea
id: steps
attributes:
label: What have you tried?
description: Describe any steps you've already taken to troubleshoot or solve the issue.
placeholder: |
- I checked the logs and saw...
- I followed the install guide and tried...
- type: input
id: version
attributes:
label: Paperless-ngx version
placeholder: e.g. 1.14.0
validations:
required: true
- type: input
id: host-os
attributes:
label: Host OS
description: Include architecture if relevant.
placeholder: e.g. Ubuntu 22.04 / Raspberry Pi arm64
- type: dropdown
id: install-method
attributes:
label: Installation method
options:
- Docker - official image
- Docker - linuxserver.io image
- Bare metal
- Other (please describe above)
- type: textarea
id: system-status
attributes:
label: System status
description: If available, copy & paste the system status output from Settings > System Status > Copy
render: json
- type: textarea
id: logs
attributes:
label: Relevant logs or output
description: If you have logs, errors that might help, paste it here.
render: bash

View File

@ -1,6 +1,5 @@
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
# Required for uv support for now
enable-beta-ecosystems: true

View File

@ -4,7 +4,6 @@
# Requires a PAT with the correct scope set in the secrets.
#
# This workflow will not trigger runs on forked repos.
name: Cleanup Image Tags
on:
delete:

View File

@ -61,7 +61,7 @@ jobs:
cd src-ui
pnpm run ng extract-i18n
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5
uses: stefanzweifel/git-auto-commit-action@v6
with:
file_pattern: 'src-ui/messages.xlf src/locale/en_US/LC_MESSAGES/django.po'
commit_message: "Auto translate strings"

View File

@ -1,7 +1,6 @@
# This file configures pre-commit hooks.
# See https://pre-commit.com/ for general information
# See https://pre-commit.com/hooks.html for a listing of possible hooks
repos:
# General hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
@ -29,7 +28,7 @@ repos:
- id: check-case-conflict
- id: detect-private-key
- repo: https://github.com/codespell-project/codespell
rev: v2.4.0
rev: v2.4.1
hooks:
- id: codespell
exclude: "(^src-ui/src/locale/)|(^src-ui/pnpm-lock.yaml)|(^src-ui/e2e/)|(^src/paperless_mail/tests/samples/)"
@ -38,7 +37,7 @@ repos:
- json
# See https://github.com/prettier/prettier/issues/15742 for the fork reason
- repo: https://github.com/rbubley/mirrors-prettier
rev: 'v3.3.3'
rev: 'v3.6.2'
hooks:
- id: prettier
types_or:
@ -50,17 +49,17 @@ repos:
- 'prettier-plugin-organize-imports@4.1.0'
# Python hooks
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.9
rev: v0.12.2
hooks:
- id: ruff
- id: ruff-format
- repo: https://github.com/tox-dev/pyproject-fmt
rev: "v2.5.1"
rev: "v2.6.0"
hooks:
- id: pyproject-fmt
# Dockerfile hooks
- repo: https://github.com/AleksaC/hadolint-py
rev: v2.12.0.3
rev: v2.12.1b3
hooks:
- id: hadolint
# Shell script hooks
@ -77,7 +76,7 @@ repos:
hooks:
- id: shellcheck
- repo: https://github.com/google/yamlfmt
rev: v0.14.0
rev: v0.17.2
hooks:
- id: yamlfmt
exclude: "^src-ui/pnpm-lock.yaml"

View File

@ -21,7 +21,7 @@ ARG PNGX_TAG_VERSION=
RUN set -eux && \
case "${PNGX_TAG_VERSION}" in \
dev|beta|fix*|feature*) \
sed -i -E "s/version: '([0-9\.]+)'/version: '\1 #${PNGX_TAG_VERSION}'/g" /src/src-ui/src/environments/environment.prod.ts \
sed -i -E "s/tag: '([a-z\.]+)'/tag: '${PNGX_TAG_VERSION}'/g" /src/src-ui/src/environments/environment.prod.ts \
;; \
esac
@ -32,7 +32,7 @@ RUN set -eux \
# Purpose: Installs s6-overlay and rootfs
# Comments:
# - Don't leave anything extra in here either
FROM ghcr.io/astral-sh/uv:0.7.9-python3.12-bookworm-slim AS s6-overlay-base
FROM ghcr.io/astral-sh/uv:0.7.19-python3.12-bookworm-slim AS s6-overlay-base
WORKDIR /usr/src/s6

View File

@ -2,7 +2,6 @@
# and Tika containers for a more end to end test of the Tika related functionality
# Can be used locally or by the CI to start the necessary containers with the
# correct networking for the tests
services:
gotenberg:
image: docker.io/gotenberg/gotenberg:8.20

View File

@ -25,11 +25,9 @@
# and '.env' into a folder.
# - Run 'docker compose pull'.
# - Run 'docker compose up -d'.
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8

View File

@ -24,7 +24,6 @@
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8

View File

@ -25,7 +25,6 @@
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8

View File

@ -28,7 +28,6 @@
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8

View File

@ -24,7 +24,6 @@
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8

View File

@ -28,7 +28,6 @@
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8

View File

@ -21,7 +21,6 @@
#
# For more extensive installation and update instructions, refer to the
# documentation.
services:
broker:
image: docker.io/library/redis:8

View File

@ -457,6 +457,22 @@ of the index and usually makes queries faster and also ensures that the
autocompletion works properly. This command is regularly invoked by the
task scheduler.
### Clearing the database read cache
If the database read cache is enabled, **you must run this command** after making any changes to the database outside the application context.
This includes operations such as restoring a database backup or executing SQL statements like UPDATE, INSERT, DELETE, ALTER, CREATE, or DROP.
Failing to invalidate the cache after such modifications can lead to stale data being served from the cache, and **may cause data corruption** or inconsistent behavior in the application.
Use the following management command to clear the cache:
```
invalidate_cachalot
```
!!! info
The database read cache is based on Django-Cachalot. You can refer to their [documentation](https://django-cachalot.readthedocs.io/en/latest/quickstart.html#manage-py-command).
### Managing filenames {#renamer}
If you use paperless' feature to

View File

@ -1,5 +1,64 @@
# Changelog
## paperless-ngx 2.17.1
### Bug Fixes
- Fix: correct PAPERLESS_EMPTY_TRASH_DIR to Path [@shamoon](https://github.com/shamoon) ([#10227](https://github.com/paperless-ngx/paperless-ngx/pull/10227))
### All App Changes
- Fix: correct PAPERLESS_EMPTY_TRASH_DIR to Path [@shamoon](https://github.com/shamoon) ([#10227](https://github.com/paperless-ngx/paperless-ngx/pull/10227))
## paperless-ngx 2.17.0
### Breaking Changes
- Fix: restore expected pre-2.16 scheduled workflow offset behavior [@shamoon](https://github.com/shamoon) ([#10218](https://github.com/paperless-ngx/paperless-ngx/pull/10218))
### Features / Enhancements
- QoL: log version at startup, show backend vs frontend mismatch in system status [@shamoon](https://github.com/shamoon) ([#10214](https://github.com/paperless-ngx/paperless-ngx/pull/10214))
- Feature: add Persian translation [@shamoon](https://github.com/shamoon) ([#10183](https://github.com/paperless-ngx/paperless-ngx/pull/10183))
- Enhancement: support import of zipped export [@kaerbr](https://github.com/kaerbr) ([#10073](https://github.com/paperless-ngx/paperless-ngx/pull/10073))
### Bug Fixes
- Fix: more api fixes [@shamoon](https://github.com/shamoon) ([#10204](https://github.com/paperless-ngx/paperless-ngx/pull/10204))
- Fix: restore expected pre-2.16 scheduled workflow offset behavior [@shamoon](https://github.com/shamoon) ([#10218](https://github.com/paperless-ngx/paperless-ngx/pull/10218))
- Fix: fix some API crashes [@shamoon](https://github.com/shamoon) ([#10196](https://github.com/paperless-ngx/paperless-ngx/pull/10196))
- Fix: remove duplicate base path in websocket urls [@robertmx](https://github.com/robertmx) ([#10194](https://github.com/paperless-ngx/paperless-ngx/pull/10194))
- Fix: use hard delete for custom fields with workflow removal [@shamoon](https://github.com/shamoon) ([#10191](https://github.com/paperless-ngx/paperless-ngx/pull/10191))
- Fix: fix mail account test api schema [@shamoon](https://github.com/shamoon) ([#10164](https://github.com/paperless-ngx/paperless-ngx/pull/10164))
- Fix: correct api schema for mail_account process [@shamoon](https://github.com/shamoon) ([#10157](https://github.com/paperless-ngx/paperless-ngx/pull/10157))
- Fix: correct api schema for next_asn [@shamoon](https://github.com/shamoon) ([#10151](https://github.com/paperless-ngx/paperless-ngx/pull/10151))
- Fix: fix email and notes endpoints api spec [@shamoon](https://github.com/shamoon) ([#10148](https://github.com/paperless-ngx/paperless-ngx/pull/10148))
### Dependencies
- Chore: bump angular/common to 19.12.14 [@shamoon](https://github.com/shamoon) ([#10212](https://github.com/paperless-ngx/paperless-ngx/pull/10212))
### All App Changes
<details>
<summary>14 changes</summary>
- QoL: log version at startup, show backend vs frontend mismatch in system status [@shamoon](https://github.com/shamoon) ([#10214](https://github.com/paperless-ngx/paperless-ngx/pull/10214))
- Fix: more api fixes [@shamoon](https://github.com/shamoon) ([#10204](https://github.com/paperless-ngx/paperless-ngx/pull/10204))
- Fix: restore expected pre-2.16 scheduled workflow offset behavior [@shamoon](https://github.com/shamoon) ([#10218](https://github.com/paperless-ngx/paperless-ngx/pull/10218))
- Chore: switch from os.path to pathlib.Path [@gothicVI](https://github.com/gothicVI) ([#9933](https://github.com/paperless-ngx/paperless-ngx/pull/9933))
- Chore: bump angular/common to 19.12.14 [@shamoon](https://github.com/shamoon) ([#10212](https://github.com/paperless-ngx/paperless-ngx/pull/10212))
- Fix: fix some API crashes [@shamoon](https://github.com/shamoon) ([#10196](https://github.com/paperless-ngx/paperless-ngx/pull/10196))
- Fix: remove duplicate base path in websocket urls [@robertmx](https://github.com/robertmx) ([#10194](https://github.com/paperless-ngx/paperless-ngx/pull/10194))
- Fix: use hard delete for custom fields with workflow removal [@shamoon](https://github.com/shamoon) ([#10191](https://github.com/paperless-ngx/paperless-ngx/pull/10191))
- Feature: add Persian translation [@shamoon](https://github.com/shamoon) ([#10183](https://github.com/paperless-ngx/paperless-ngx/pull/10183))
- Enhancement: support import of zipped export [@kaerbr](https://github.com/kaerbr) ([#10073](https://github.com/paperless-ngx/paperless-ngx/pull/10073))
- Fix: fix mail account test api schema [@shamoon](https://github.com/shamoon) ([#10164](https://github.com/paperless-ngx/paperless-ngx/pull/10164))
- Fix: correct api schema for mail_account process [@shamoon](https://github.com/shamoon) ([#10157](https://github.com/paperless-ngx/paperless-ngx/pull/10157))
- Fix: correct api schema for next_asn [@shamoon](https://github.com/shamoon) ([#10151](https://github.com/paperless-ngx/paperless-ngx/pull/10151))
- Fix: fix email and notes endpoints api spec [@shamoon](https://github.com/shamoon) ([#10148](https://github.com/paperless-ngx/paperless-ngx/pull/10148))
</details>
## paperless-ngx 2.16.3
### Features / Enhancements
@ -5948,7 +6007,6 @@ primarily.
a very good job at ocr'ing a document with the default
language. Certain language specifics such as umlauts may not get
picked up properly.
- `PAPERLESS_DEBUG` defaults to `false`.
- The presence of `PAPERLESS_DBHOST` now determines whether to use
PostgreSQL or SQLite.
- `PAPERLESS_OCR_THREADS` is gone and replaced with

View File

@ -159,6 +159,41 @@ Available options are `postgresql` and `mariadb`.
Defaults to unset, which uses Djangos built-in defaults.
#### [`PAPERLESS_DB_READ_CACHE_ENABLED=<bool>`](#PAPERLESS_DB_READ_CACHE_ENABLED) {#PAPERLESS_DB_READ_CACHE_ENABLED}
: Caches the database read query results into Redis. This can significantly improve application response times by caching database queries, at the cost of slightly increased memory usage.
Defaults to `false`.
!!! danger
**Do not modify the database outside the application while it is running.**
This includes actions such as restoring a backup, upgrading the database, or performing manual inserts. All external modifications must be done **only when the application is stopped**.
After making any such changes, you **must invalidate the DB read cache** using the `invalidate_cachalot` management command.
#### [`PAPERLESS_READ_CACHE_TTL=<int>`](#PAPERLESS_READ_CACHE_TTL) {#PAPERLESS_READ_CACHE_TTL}
: Specifies how long (in seconds) read data should be cached.
Allowed values are between `1` (one second) and `31536000` (one year). Defaults to `3600` (one hour).
!!! warning
A high TTL increases memory usage over time. Memory may be used until end of TTL, even if the cache is invalidated with the `invalidate_cachalot` command.
In case of an out-of-memory (OOM) situation, Redis may stop accepting new data — including cache entries, scheduled tasks, and documents to consume.
If your system has limited RAM, consider configuring a dedicated Redis instance for the read cache, with a memory limit and the eviction policy set to `allkeys-lru`.
For more details, refer to the [Redis eviction policy documentation](https://redis.io/docs/latest/develop/reference/eviction/), and see the `PAPERLESS_READ_CACHE_REDIS_URL` setting to specify a separate Redis broker.
#### [`PAPERLESS_READ_CACHE_REDIS_URL=<url>`](#PAPERLESS_READ_CACHE_REDIS_URL) {#PAPERLESS_READ_CACHE_REDIS_URL}
: Defines the Redis instance used for the read cache.
Defaults to `None`.
!!! Note
If this value is not set, the same Redis instance used for scheduled tasks will be used for caching as well.
## Optional Services
### Tika {#tika}
@ -968,6 +1003,22 @@ still perform some basic text pre-processing before matching.
Defaults to 1.
#### [`PAPERLESS_DATE_PARSER_LANGUAGES=<lang>`](#PAPERLESS_DATE_PARSER_LANGUAGES) {#PAPERLESS_DATE_PARSER_LANGUAGES}
Specifies which language Paperless should use when parsing dates from documents.
This should be a language code supported by the dateparser library,
for example: "en", or a combination such as "en+de".
Locales are also supported (e.g., "en-AU").
Multiple languages can be combined using "+", for example: "en+de" or "en-AU+de".
For valid values, refer to the list of supported languages and locales in the [dateparser documentation](https://dateparser.readthedocs.io/en/latest/supported_locales.html).
Set this to match the languages in which most of your documents are written.
If not set, Paperless will attempt to infer the language(s) from the OCR configuration (`PAPERLESS_OCR_LANGUAGE`).
!!! note
This format differs from the `PAPERLESS_OCR_LANGUAGE` setting, which uses ISO 639-2 codes (3 letters, e.g., "eng+deu" for Tesseract OCR).
#### [`PAPERLESS_EMAIL_TASK_CRON=<cron expression>`](#PAPERLESS_EMAIL_TASK_CRON) {#PAPERLESS_EMAIL_TASK_CRON}
: Configures the scheduled email fetching frequency. The value

View File

@ -408,7 +408,7 @@ Currently, there are three events that correspond to workflow trigger 'types':
tags, doc type, or correspondent.
4. **Scheduled**: a scheduled trigger that can be used to run workflows at a specific time. The date used can be either the document
added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date (positive
offsets will trigger before the date, negative offsets will trigger after).
offsets will trigger after the date, negative offsets will trigger before).
The following flow diagram illustrates the three document trigger types:

View File

@ -1,10 +1,6 @@
# Have a look at the docs for documentation.
# https://docs.paperless-ngx.com/configuration/
# Debug. Only enable this for development.
#PAPERLESS_DEBUG=false
# Required services
#PAPERLESS_REDIS=redis://localhost:6379

View File

@ -1,6 +1,6 @@
[project]
name = "paperless-ngx"
version = "2.16.3"
version = "2.17.1"
description = "A community-supported supercharged version of paperless: scan, index and archive all your physical documents"
readme = "README.md"
requires-python = ">=3.10"
@ -27,6 +27,7 @@ dependencies = [
"django~=5.1.7",
"django-allauth[socialaccount,mfa]~=65.4.0",
"django-auditlog~=3.1.2",
"django-cachalot~=2.8.0",
"django-celery-results~=2.6.0",
"django-compression-middleware~=0.5.0",
"django-cors-headers~=4.7.0",
@ -44,13 +45,13 @@ dependencies = [
"flower~=2.0.1",
"gotenberg-client~=0.10.0",
"httpx-oauth~=0.16",
"imap-tools~=1.10.0",
"imap-tools~=1.11.0",
"inotifyrecursive~=0.3",
"jinja2~=3.1.5",
"langdetect~=1.0.9",
"nltk~=3.9.1",
"ocrmypdf~=16.10.0",
"pathvalidate~=3.2.3",
"pathvalidate~=3.3.1",
"pdf2image~=1.17.0",
"python-dateutil~=2.9.0",
"python-dotenv~=1.1.0",
@ -60,7 +61,7 @@ dependencies = [
"pyzbar~=0.1.9",
"rapidfuzz~=3.13.0",
"redis[hiredis]~=5.2.1",
"scikit-learn~=1.6.1",
"scikit-learn~=1.7.0",
"setproctitle~=1.3.4",
"tika-client~=0.9.0",
"tqdm~=4.67.1",
@ -74,12 +75,12 @@ optional-dependencies.mariadb = [
"mysqlclient~=2.2.7",
]
optional-dependencies.postgres = [
"psycopg[c]==3.2.5",
"psycopg[c]==3.2.9",
# Direct dependency for proper resolution of the pre-built wheels
"psycopg-c==3.2.5",
"psycopg-c==3.2.9",
]
optional-dependencies.webserver = [
"granian[uvloop]~=2.3.2",
"granian[uvloop]~=2.4.1",
]
[dependency-groups]
@ -113,7 +114,7 @@ testing = [
lint = [
"pre-commit~=4.1.0",
"pre-commit-uv~=4.1.3",
"ruff~=0.9.9",
"ruff~=0.12.2",
]
typing = [
@ -173,6 +174,7 @@ lint.extend-select = [
]
lint.ignore = [
"DJ001",
"PLC0415",
"RUF012",
"SIM105",
]
@ -222,22 +224,9 @@ lint.per-file-ignores."src/documents/parsers.py" = [
lint.per-file-ignores."src/documents/signals/handlers.py" = [
"PTH",
] # TODO Enable & remove
lint.per-file-ignores."src/documents/views.py" = [
"PTH",
] # TODO Enable & remove
lint.per-file-ignores."src/paperless/checks.py" = [
"PTH",
] # TODO Enable & remove
lint.per-file-ignores."src/paperless/settings.py" = [
"PTH",
] # TODO Enable & remove
lint.per-file-ignores."src/paperless_mail/mail.py" = [
"PTH",
] # TODO Enable & remove
lint.per-file-ignores."src/paperless_tesseract/tests/test_parser.py" = [
"PTH",
"RUF001",
] # TODO PTH Enable & remove
]
lint.isort.force-single-line = true
[tool.pytest.ini_options]
@ -251,6 +240,7 @@ testpaths = [
"src/paperless_mail/tests/",
"src/paperless_tesseract/tests/",
"src/paperless_tika/tests",
"src/paperless_remote/tests/",
]
addopts = [
"--pythonwarnings=all",
@ -314,8 +304,8 @@ environments = [
[tool.uv.sources]
# Markers are chosen to select these almost exclusively when building the Docker image
psycopg-c = [
{ url = "https://github.com/paperless-ngx/builder/releases/download/psycopg-3.2.5/psycopg_c-3.2.5-cp312-cp312-linux_x86_64.whl", marker = "sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.12'" },
{ url = "https://github.com/paperless-ngx/builder/releases/download/psycopg-3.2.5/psycopg_c-3.2.5-cp312-cp312-linux_aarch64.whl", marker = "sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.12'" },
{ url = "https://github.com/paperless-ngx/builder/releases/download/psycopg-3.2.9/psycopg_c-3.2.9-cp312-cp312-linux_x86_64.whl", marker = "sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.12'" },
{ url = "https://github.com/paperless-ngx/builder/releases/download/psycopg-3.2.9/psycopg_c-3.2.9-cp312-cp312-linux_aarch64.whl", marker = "sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.12'" },
]
zxing-cpp = [
{ url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_x86_64.whl", marker = "sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.12'" },

View File

@ -48,6 +48,7 @@
"sv-SE": "src/locale/messages.sv_SE.xlf",
"tr-TR": "src/locale/messages.tr_TR.xlf",
"uk-UA": "src/locale/messages.uk_UA.xlf",
"vi-VN": "src/locale/messages.vi_VN.xlf",
"zh-CN": "src/locale/messages.zh_CN.xlf",
"zh-TW": "src/locale/messages.zh_TW.xlf"
}
@ -60,10 +61,12 @@
"path": "./extra-webpack.config.ts"
},
"outputPath": "dist/paperless-ui",
"main": "src/main.ts",
"outputHashing": "none",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"polyfills": [
"src/polyfills.ts"
],
"tsConfig": "tsconfig.app.json",
"localize": true,
"assets": [
@ -86,12 +89,15 @@
"file-saver",
"utif"
],
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
"namedChunks": true,
"stylePreprocessorOptions": {
"includePaths": [
"."
]
}
},
"configurations": {
"production": {
@ -107,8 +113,6 @@
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
@ -188,6 +192,30 @@
},
"@angular-eslint/schematics:library": {
"setParserOptionsProject": true
},
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "paperless-ngx-ui",
"version": "2.16.3",
"version": "2.17.1",
"scripts": {
"preinstall": "npx only-allow pnpm",
"ng": "ng",
@ -11,28 +11,28 @@
},
"private": true,
"dependencies": {
"@angular/cdk": "^19.2.14",
"@angular/common": "~19.2.14",
"@angular/compiler": "~19.2.14",
"@angular/core": "~19.2.14",
"@angular/forms": "~19.2.14",
"@angular/localize": "~19.2.14",
"@angular/platform-browser": "~19.2.14",
"@angular/platform-browser-dynamic": "~19.2.14",
"@angular/router": "~19.2.14",
"@ng-bootstrap/ng-bootstrap": "^18.0.0",
"@ng-select/ng-select": "^14.9.0",
"@angular/cdk": "^20.0.4",
"@angular/common": "~20.0.6",
"@angular/compiler": "~20.0.6",
"@angular/core": "~20.0.6",
"@angular/forms": "~20.0.6",
"@angular/localize": "~20.0.6",
"@angular/platform-browser": "~20.0.6",
"@angular/platform-browser-dynamic": "~20.0.6",
"@angular/router": "~20.0.6",
"@ng-bootstrap/ng-bootstrap": "^19.0.1",
"@ng-select/ng-select": "^15.1.3",
"@ngneat/dirty-check-forms": "^3.0.3",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.6",
"bootstrap": "^5.3.7",
"file-saver": "^2.0.5",
"mime-names": "^1.0.0",
"ng2-pdf-viewer": "^10.4.0",
"ngx-bootstrap-icons": "^1.9.3",
"ngx-color": "^10.0.0",
"ngx-cookie-service": "^19.1.2",
"ngx-device-detector": "^9.0.0",
"ngx-ui-tour-ng-bootstrap": "^16.0.0",
"ngx-cookie-service": "^20.0.1",
"ngx-device-detector": "^10.0.2",
"ngx-ui-tour-ng-bootstrap": "^17.0.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"utif": "^3.1.0",
@ -40,26 +40,26 @@
"zone.js": "^0.15.1"
},
"devDependencies": {
"@angular-builders/custom-webpack": "^19.0.1",
"@angular-builders/jest": "^19.0.1",
"@angular-devkit/build-angular": "^19.2.14",
"@angular-devkit/core": "^19.2.14",
"@angular-devkit/schematics": "^19.2.14",
"@angular-eslint/builder": "19.7.0",
"@angular-eslint/eslint-plugin": "19.7.0",
"@angular-eslint/eslint-plugin-template": "19.7.0",
"@angular-eslint/schematics": "19.7.0",
"@angular-eslint/template-parser": "19.7.0",
"@angular/cli": "~19.2.14",
"@angular/compiler-cli": "~19.2.14",
"@angular-builders/custom-webpack": "^20.0.0",
"@angular-builders/jest": "^20.0.0",
"@angular-devkit/core": "^20.0.4",
"@angular-devkit/schematics": "^20.0.4",
"@angular-eslint/builder": "20.1.1",
"@angular-eslint/eslint-plugin": "20.1.1",
"@angular-eslint/eslint-plugin-template": "20.1.1",
"@angular-eslint/schematics": "20.1.1",
"@angular-eslint/template-parser": "20.1.1",
"@angular/build": "^20.0.4",
"@angular/cli": "~20.0.4",
"@angular/compiler-cli": "~20.0.6",
"@codecov/webpack-plugin": "^1.9.1",
"@playwright/test": "^1.51.1",
"@playwright/test": "^1.53.2",
"@types/jest": "^29.5.14",
"@types/node": "^22.15.29",
"@typescript-eslint/eslint-plugin": "^8.33.0",
"@typescript-eslint/parser": "^8.33.0",
"@typescript-eslint/utils": "^8.33.0",
"eslint": "^9.28.0",
"@types/node": "^24.0.10",
"@typescript-eslint/eslint-plugin": "^8.35.1",
"@typescript-eslint/parser": "^8.35.1",
"@typescript-eslint/utils": "^8.35.1",
"eslint": "^9.30.1",
"jest": "29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-junit": "^16.0.0",
@ -67,7 +67,8 @@
"jest-websocket-mock": "^2.5.0",
"prettier-plugin-organize-imports": "^4.1.0",
"ts-node": "~10.9.1",
"typescript": "^5.5.4"
"typescript": "^5.8.3",
"webpack": "^5.99.9"
},
"pnpm": {
"onlyBuiltDependencies": [
@ -77,6 +78,5 @@
"lmdb",
"msgpackr-extract"
]
},
"typings": "./src/typings.d.ts"
}
}

4074
src-ui/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,7 @@ import localeSr from '@angular/common/locales/sr'
import localeSv from '@angular/common/locales/sv'
import localeTr from '@angular/common/locales/tr'
import localeUk from '@angular/common/locales/uk'
import localeVi from '@angular/common/locales/vi'
import localeZh from '@angular/common/locales/zh'
import localeZhHant from '@angular/common/locales/zh-Hant'
@ -75,6 +76,7 @@ registerLocaleData(localeSr)
registerLocaleData(localeSv)
registerLocaleData(localeTr)
registerLocaleData(localeUk)
registerLocaleData(localeVi)
registerLocaleData(localeZh)
registerLocaleData(localeZhHant)

View File

@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit, Renderer2 } from '@angular/core'
import { Component, inject, OnDestroy, OnInit, Renderer2 } from '@angular/core'
import { Router, RouterOutlet } from '@angular/router'
import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap'
import { first, Subscription } from 'rxjs'
@ -29,22 +29,22 @@ import { WebsocketStatusService } from './services/websocket-status.service'
],
})
export class AppComponent implements OnInit, OnDestroy {
private settings = inject(SettingsService)
private websocketStatusService = inject(WebsocketStatusService)
private toastService = inject(ToastService)
private router = inject(Router)
private tasksService = inject(TasksService)
tourService = inject(TourService)
private renderer = inject(Renderer2)
private permissionsService = inject(PermissionsService)
private hotKeyService = inject(HotKeyService)
private componentRouterService = inject(ComponentRouterService)
newDocumentSubscription: Subscription
successSubscription: Subscription
failedSubscription: Subscription
constructor(
private settings: SettingsService,
private websocketStatusService: WebsocketStatusService,
private toastService: ToastService,
private router: Router,
private tasksService: TasksService,
public tourService: TourService,
private renderer: Renderer2,
private permissionsService: PermissionsService,
private hotKeyService: HotKeyService,
private componentRouterService: ComponentRouterService
) {
constructor() {
let anyWindow = window as any
anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.mjs'
this.settings.updateAppearanceSettings()

View File

@ -1,5 +1,5 @@
import { AsyncPipe } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import {
AbstractControl,
FormControl,
@ -57,6 +57,10 @@ export class ConfigComponent
extends LoadingComponentWithPermissions
implements OnInit, OnDestroy, DirtyComponent
{
private configService = inject(ConfigService)
private toastService = inject(ToastService)
private settingsService = inject(SettingsService)
public readonly ConfigOptionType = ConfigOptionType
// generated dynamically
@ -77,11 +81,7 @@ export class ConfigComponent
storeSub: Subscription
isDirty$: Observable<boolean>
constructor(
private configService: ConfigService,
private toastService: ToastService,
private settingsService: SettingsService
) {
constructor() {
super()
this.configForm.addControl('id', new FormControl())
PaperlessConfigOptions.forEach((option) => {

View File

@ -5,6 +5,7 @@ import {
OnDestroy,
OnInit,
ViewChild,
inject,
} from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'
@ -28,12 +29,8 @@ export class LogsComponent
extends LoadingComponentWithPermissions
implements OnInit, OnDestroy
{
constructor(
private logService: LogService,
private changedetectorRef: ChangeDetectorRef
) {
super()
}
private logService = inject(LogService)
private changedetectorRef = inject(ChangeDetectorRef)
public logs: string[] = []

View File

@ -2,10 +2,10 @@ import { AsyncPipe, ViewportScroller } from '@angular/common'
import {
AfterViewInit,
Component,
Inject,
LOCALE_ID,
OnDestroy,
OnInit,
inject,
} from '@angular/core'
import {
FormControl,
@ -104,6 +104,20 @@ export class SettingsComponent
extends ComponentWithPermissions
implements OnInit, AfterViewInit, OnDestroy, DirtyComponent
{
private documentListViewService = inject(DocumentListViewService)
private toastService = inject(ToastService)
private settings = inject(SettingsService)
currentLocale = inject(LOCALE_ID)
private viewportScroller = inject(ViewportScroller)
private activatedRoute = inject(ActivatedRoute)
readonly tourService = inject(TourService)
private usersService = inject(UserService)
private groupsService = inject(GroupService)
private router = inject(Router)
permissionsService = inject(PermissionsService)
private modalService = inject(NgbModal)
private systemStatusService = inject(SystemStatusService)
activeNavID: number
settingsForm = new FormGroup({
@ -179,21 +193,7 @@ export class SettingsComponent
)
}
constructor(
private documentListViewService: DocumentListViewService,
private toastService: ToastService,
private settings: SettingsService,
@Inject(LOCALE_ID) public currentLocale: string,
private viewportScroller: ViewportScroller,
private activatedRoute: ActivatedRoute,
public readonly tourService: TourService,
private usersService: UserService,
private groupsService: GroupService,
private router: Router,
public permissionsService: PermissionsService,
private modalService: NgbModal,
private systemStatusService: SystemStatusService
) {
constructor() {
super()
this.settings.settingsSaved.subscribe(() => {
if (!this.savePending) this.initialize()

View File

@ -1,5 +1,5 @@
import { NgTemplateOutlet, SlicePipe } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, inject, OnDestroy, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import {
@ -69,6 +69,10 @@ export class TasksComponent
extends LoadingComponentWithPermissions
implements OnInit, OnDestroy
{
tasksService = inject(TasksService)
private modalService = inject(NgbModal)
private readonly router = inject(Router)
public activeTab: TaskTab
public selectedTasks: Set<number> = new Set()
public togggleAll: boolean = false
@ -105,14 +109,6 @@ export class TasksComponent
: $localize`Dismiss all`
}
constructor(
public tasksService: TasksService,
private modalService: NgbModal,
private readonly router: Router
) {
super()
}
ngOnInit() {
this.tasksService.reload()
timer(5000, 5000)

View File

@ -1,4 +1,4 @@
import { Component, OnDestroy } from '@angular/core'
import { Component, OnDestroy, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import {
@ -36,19 +36,19 @@ export class TrashComponent
extends LoadingComponentWithPermissions
implements OnDestroy
{
private trashService = inject(TrashService)
private toastService = inject(ToastService)
private modalService = inject(NgbModal)
private settingsService = inject(SettingsService)
private router = inject(Router)
public documentsInTrash: Document[] = []
public selectedDocuments: Set<number> = new Set()
public allToggled: boolean = false
public page: number = 1
public totalDocuments: number
constructor(
private trashService: TrashService,
private toastService: ToastService,
private modalService: NgbModal,
private settingsService: SettingsService,
private router: Router
) {
constructor() {
super()
this.reload()
}

View File

@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Subject, first, takeUntil } from 'rxjs'
@ -31,22 +31,18 @@ export class UsersAndGroupsComponent
extends ComponentWithPermissions
implements OnInit, OnDestroy
{
private usersService = inject(UserService)
private groupsService = inject(GroupService)
private toastService = inject(ToastService)
private modalService = inject(NgbModal)
permissionsService = inject(PermissionsService)
private settings = inject(SettingsService)
users: User[]
groups: Group[]
unsubscribeNotifier: Subject<any> = new Subject()
constructor(
private usersService: UserService,
private groupsService: GroupService,
private toastService: ToastService,
private modalService: NgbModal,
public permissionsService: PermissionsService,
private settings: SettingsService
) {
super()
}
ngOnInit(): void {
this.usersService
.listAll(null, null, { full_perms: true })

View File

@ -6,7 +6,7 @@ import {
moveItemInArray,
} from '@angular/cdk/drag-drop'
import { NgClass } from '@angular/common'
import { Component, HostListener, OnInit } from '@angular/core'
import { Component, HostListener, inject, OnInit } from '@angular/core'
import { ActivatedRoute, Router, RouterModule } from '@angular/router'
import {
NgbCollapseModule,
@ -74,27 +74,27 @@ export class AppFrameComponent
extends ComponentWithPermissions
implements OnInit, ComponentCanDeactivate
{
versionString = `${environment.appTitle} ${environment.version}`
router = inject(Router)
private activatedRoute = inject(ActivatedRoute)
private openDocumentsService = inject(OpenDocumentsService)
savedViewService = inject(SavedViewService)
private remoteVersionService = inject(RemoteVersionService)
settingsService = inject(SettingsService)
tasksService = inject(TasksService)
private readonly toastService = inject(ToastService)
private modalService = inject(NgbModal)
permissionsService = inject(PermissionsService)
private djangoMessagesService = inject(DjangoMessagesService)
appRemoteVersion: AppRemoteVersion
isMenuCollapsed: boolean = true
slimSidebarAnimating: boolean = false
constructor(
public router: Router,
private activatedRoute: ActivatedRoute,
private openDocumentsService: OpenDocumentsService,
public savedViewService: SavedViewService,
private remoteVersionService: RemoteVersionService,
public settingsService: SettingsService,
public tasksService: TasksService,
private readonly toastService: ToastService,
private modalService: NgbModal,
public permissionsService: PermissionsService,
private djangoMessagesService: DjangoMessagesService
) {
constructor() {
super()
const permissionsService = this.permissionsService
if (
permissionsService.currentUserCan(
@ -142,6 +142,10 @@ export class AppFrameComponent
}, 200) // slightly longer than css animation for slim sidebar
}
get versionString(): string {
return `${environment.appTitle} v${this.settingsService.get(SETTINGS_KEYS.VERSION)}${environment.production ? '' : ` #${environment.tag}`}`
}
get customAppTitle(): string {
return this.settingsService.get(SETTINGS_KEYS.APP_TITLE)
}

View File

@ -6,6 +6,7 @@ import {
QueryList,
ViewChild,
ViewChildren,
inject,
} from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router'
@ -69,6 +70,17 @@ import { WorkflowEditDialogComponent } from '../../common/edit-dialog/workflow-e
],
})
export class GlobalSearchComponent implements OnInit {
searchService = inject(SearchService)
private router = inject(Router)
private modalService = inject(NgbModal)
private documentService = inject(DocumentService)
private documentListViewService = inject(DocumentListViewService)
private permissionsService = inject(PermissionsService)
private toastService = inject(ToastService)
private hotkeyService = inject(HotKeyService)
private settingsService = inject(SettingsService)
private locationStrategy = inject(LocationStrategy)
public DataType = DataType
public query: string
public queryDebounce: Subject<string>
@ -90,18 +102,7 @@ export class GlobalSearchComponent implements OnInit {
)
}
constructor(
public searchService: SearchService,
private router: Router,
private modalService: NgbModal,
private documentService: DocumentService,
private documentListViewService: DocumentListViewService,
private permissionsService: PermissionsService,
private toastService: ToastService,
private hotkeyService: HotKeyService,
private settingsService: SettingsService,
private locationStrategy: LocationStrategy
) {
constructor() {
this.queryDebounce = new Subject<string>()
this.queryDebounce

View File

@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import {
NgbDropdownModule,
NgbProgressbarModule,
@ -20,7 +20,7 @@ import { ToastComponent } from '../../common/toast/toast.component'
],
})
export class ToastsDropdownComponent implements OnInit, OnDestroy {
constructor(public toastService: ToastService) {}
toastService = inject(ToastService)
private subscription: Subscription

View File

@ -1,5 +1,5 @@
import { DecimalPipe } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core'
import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Subject } from 'rxjs'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
@ -12,9 +12,7 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
imports: [DecimalPipe, SafeHtmlPipe],
})
export class ConfirmDialogComponent extends LoadingComponentWithPermissions {
constructor(public activeModal: NgbActiveModal) {
super()
}
activeModal = inject(NgbActiveModal)
@Output()
public confirmClicked = new EventEmitter()

View File

@ -1,6 +1,5 @@
import { Component, TemplateRef, ViewChild } from '@angular/core'
import { Component, TemplateRef, ViewChild, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import {
PDFDocumentProxy,
PdfViewerComponent,
@ -17,6 +16,8 @@ import { ConfirmDialogComponent } from '../confirm-dialog.component'
imports: [PdfViewerModule, FormsModule, ReactiveFormsModule, SafeHtmlPipe],
})
export class DeletePagesConfirmDialogComponent extends ConfirmDialogComponent {
private documentService = inject(DocumentService)
public documentID: number
public pages: number[] = []
public currentPage: number = 1
@ -34,11 +35,8 @@ export class DeletePagesConfirmDialogComponent extends ConfirmDialogComponent {
return this.documentService.getPreviewUrl(this.documentID)
}
constructor(
activeModal: NgbActiveModal,
private documentService: DocumentService
) {
super(activeModal)
constructor() {
super()
}
public pdfPreviewLoaded(pdf: PDFDocumentProxy) {

View File

@ -3,9 +3,8 @@ import {
DragDropModule,
moveItemInArray,
} from '@angular/cdk/drag-drop'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { takeUntil } from 'rxjs'
import { Document } from 'src/app/data/document'
@ -28,6 +27,9 @@ export class MergeConfirmDialogComponent
extends ConfirmDialogComponent
implements OnInit
{
private documentService = inject(DocumentService)
private permissionService = inject(PermissionsService)
public documentIDs: number[] = []
public archiveFallback: boolean = false
public deleteOriginals: boolean = false
@ -38,12 +40,8 @@ export class MergeConfirmDialogComponent
public metadataDocumentID: number = -1
constructor(
activeModal: NgbActiveModal,
private documentService: DocumentService,
private permissionService: PermissionsService
) {
super(activeModal)
constructor() {
super()
}
ngOnInit() {

View File

@ -1,6 +1,5 @@
import { NgStyle } from '@angular/common'
import { Component } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Component, inject } from '@angular/core'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { DocumentService } from 'src/app/services/rest/document.service'
@ -13,6 +12,8 @@ import { ConfirmDialogComponent } from '../confirm-dialog.component'
imports: [NgStyle, NgxBootstrapIconsModule, SafeHtmlPipe],
})
export class RotateConfirmDialogComponent extends ConfirmDialogComponent {
documentService = inject(DocumentService)
public documentID: number
public showPDFNote: boolean = true
@ -25,11 +26,8 @@ export class RotateConfirmDialogComponent extends ConfirmDialogComponent {
return degrees
}
constructor(
activeModal: NgbActiveModal,
public documentService: DocumentService
) {
super(activeModal)
constructor() {
super()
}
rotate(clockwise: boolean = true) {

View File

@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { PDFDocumentProxy, PdfViewerModule } from 'ng2-pdf-viewer'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Document } from 'src/app/data/document'
@ -23,6 +22,9 @@ export class SplitConfirmDialogComponent
extends ConfirmDialogComponent
implements OnInit
{
private documentService = inject(DocumentService)
private permissionService = inject(PermissionsService)
public get pagesString(): string {
let pagesStr = ''
@ -62,12 +64,8 @@ export class SplitConfirmDialogComponent
return this.documentService.getPreviewUrl(this.documentID)
}
constructor(
activeModal: NgbActiveModal,
private documentService: DocumentService,
private permissionService: PermissionsService
) {
super(activeModal)
constructor() {
super()
this.confirmButtonEnabled = this.pages.size > 0
}

View File

@ -1,5 +1,5 @@
import { CurrencyPipe, getLocaleCurrencyCode } from '@angular/common'
import { Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'
import { Component, Input, LOCALE_ID, OnInit, inject } from '@angular/core'
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { takeUntil } from 'rxjs'
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
@ -20,6 +20,9 @@ export class CustomFieldDisplayComponent
extends LoadingComponentWithPermissions
implements OnInit
{
private customFieldService = inject(CustomFieldsService)
private documentService = inject(DocumentService)
CustomFieldDataType = CustomFieldDataType
private _document: Document
@ -63,11 +66,9 @@ export class CustomFieldDisplayComponent
private defaultCurrencyCode: any
constructor(
private customFieldService: CustomFieldsService,
private documentService: DocumentService,
@Inject(LOCALE_ID) currentLocale: string
) {
constructor() {
const currentLocale = inject(LOCALE_ID)
super()
this.defaultCurrencyCode = getLocaleCurrencyCode(currentLocale)
this.customFieldService.listAll().subscribe((r) => {

View File

@ -7,6 +7,7 @@ import {
QueryList,
ViewChild,
ViewChildren,
inject,
} from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap'
@ -37,6 +38,11 @@ import { CustomFieldEditDialogComponent } from '../edit-dialog/custom-field-edit
],
})
export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissions {
private customFieldsService = inject(CustomFieldsService)
private modalService = inject(NgbModal)
private toastService = inject(ToastService)
private permissionsService = inject(PermissionsService)
public popperOptions = pngxPopperOptions
@Input()
@ -78,12 +84,7 @@ export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissio
)
}
constructor(
private customFieldsService: CustomFieldsService,
private modalService: NgbModal,
private toastService: ToastService,
private permissionsService: PermissionsService
) {
constructor() {
super()
this.getFields()
}

View File

@ -2,6 +2,7 @@ import { NgTemplateOutlet } from '@angular/common'
import {
Component,
EventEmitter,
inject,
Input,
Output,
QueryList,
@ -178,6 +179,8 @@ export class CustomFieldQueriesModel {
],
})
export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPermissions {
protected customFieldsService = inject(CustomFieldsService)
public CustomFieldQueryComponentType = CustomFieldQueryElementType
public CustomFieldQueryOperator = CustomFieldQueryOperator
public CustomFieldDataType = CustomFieldDataType
@ -245,7 +248,7 @@ export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPerm
public readonly today: string = new Date().toISOString().split('T')[0]
constructor(protected customFieldsService: CustomFieldsService) {
constructor() {
super()
this.selectionModel = new CustomFieldQueriesModel()
this.getFields()

View File

@ -6,6 +6,7 @@ import {
OnDestroy,
OnInit,
Output,
inject,
} from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import {
@ -63,7 +64,9 @@ export enum RelativeDate {
export class DatesDropdownComponent implements OnInit, OnDestroy {
public popperOptions = pngxPopperOptions
constructor(settings: SettingsService) {
constructor() {
const settings = inject(SettingsService)
this.datePlaceHolder = settings.getLocalizedDateInputFormat()
}

View File

@ -13,8 +13,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></pngx-input-check>
}

View File

@ -1,11 +1,10 @@
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Correspondent } from 'src/app/data/correspondent'
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
@ -13,6 +12,7 @@ import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
import { UserService } from 'src/app/services/rest/user.service'
import { SettingsService } from 'src/app/services/settings.service'
import { CheckComponent } from '../../input/check/check.component'
import { PermissionsFormComponent } from '../../input/permissions/permissions-form/permissions-form.component'
import { SelectComponent } from '../../input/select/select.component'
import { TextComponent } from '../../input/text/text.component'
@ -22,6 +22,7 @@ import { TextComponent } from '../../input/text/text.component'
templateUrl: './correspondent-edit-dialog.component.html',
styleUrls: ['./correspondent-edit-dialog.component.scss'],
imports: [
CheckComponent,
SelectComponent,
PermissionsFormComponent,
TextComponent,
@ -31,13 +32,11 @@ import { TextComponent } from '../../input/text/text.component'
],
})
export class CorrespondentEditDialogComponent extends EditDialogComponent<Correspondent> {
constructor(
service: CorrespondentService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(CorrespondentService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
}
getCreateTitle() {

View File

@ -5,6 +5,7 @@ import {
OnInit,
QueryList,
ViewChildren,
inject,
} from '@angular/core'
import {
FormArray,
@ -13,7 +14,6 @@ import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { takeUntil } from 'rxjs'
import {
@ -54,13 +54,11 @@ export class CustomFieldEditDialogComponent
.select_options as FormArray
}
constructor(
service: CustomFieldsService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(CustomFieldsService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
}
ngOnInit(): void {

View File

@ -14,8 +14,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
}
</div>

View File

@ -1,11 +1,10 @@
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { DocumentType } from 'src/app/data/document-type'
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
@ -13,6 +12,7 @@ import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
import { UserService } from 'src/app/services/rest/user.service'
import { SettingsService } from 'src/app/services/settings.service'
import { CheckComponent } from '../../input/check/check.component'
import { PermissionsFormComponent } from '../../input/permissions/permissions-form/permissions-form.component'
import { SelectComponent } from '../../input/select/select.component'
import { TextComponent } from '../../input/text/text.component'
@ -22,6 +22,7 @@ import { TextComponent } from '../../input/text/text.component'
templateUrl: './document-type-edit-dialog.component.html',
styleUrls: ['./document-type-edit-dialog.component.scss'],
imports: [
CheckComponent,
SelectComponent,
PermissionsFormComponent,
TextComponent,
@ -31,13 +32,11 @@ import { TextComponent } from '../../input/text/text.component'
],
})
export class DocumentTypeEditDialogComponent extends EditDialogComponent<DocumentType> {
constructor(
service: DocumentTypeService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(DocumentTypeService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
}
getCreateTitle() {

View File

@ -41,13 +41,9 @@ import { EditDialogComponent, EditDialogMode } from './edit-dialog.component'
imports: [FormsModule, ReactiveFormsModule],
})
class TestComponent extends EditDialogComponent<Tag> {
constructor(
service: TagService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = TestBed.inject(TagService)
}
getForm(): FormGroup<any> {

View File

@ -1,4 +1,11 @@
import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'
import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
inject,
} from '@angular/core'
import { FormGroup } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Observable } from 'rxjs'
@ -29,14 +36,12 @@ export abstract class EditDialogComponent<
extends LoadingComponentWithPermissions
implements OnInit
{
constructor(
protected service: AbstractPaperlessService<T>,
private activeModal: NgbActiveModal,
private userService: UserService,
protected settingsService: SettingsService
) {
super()
}
protected service = inject<AbstractPaperlessService<T>>(
AbstractPaperlessService
)
protected activeModal = inject(NgbActiveModal)
protected userService = inject(UserService)
protected settingsService = inject(SettingsService)
users: User[]

View File

@ -1,11 +1,10 @@
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Group } from 'src/app/data/group'
import { GroupService } from 'src/app/services/rest/group.service'
@ -26,13 +25,11 @@ import { PermissionsSelectComponent } from '../../permissions-select/permissions
],
})
export class GroupEditDialogComponent extends EditDialogComponent<Group> {
constructor(
service: GroupService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(GroupService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
}
getCreateTitle() {
@ -46,7 +43,7 @@ export class GroupEditDialogComponent extends EditDialogComponent<Group> {
getForm(): FormGroup {
return new FormGroup({
name: new FormControl(''),
permissions: new FormControl(null),
permissions: new FormControl([]),
})
}
}

View File

@ -1,15 +1,11 @@
import { Component, ViewChild } from '@angular/core'
import { Component, ViewChild, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import {
NgbActiveModal,
NgbAlert,
NgbAlertModule,
} from '@ng-bootstrap/ng-bootstrap'
import { NgbAlert, NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { IMAPSecurity, MailAccount } from 'src/app/data/mail-account'
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
@ -47,13 +43,11 @@ export class MailAccountEditDialogComponent extends EditDialogComponent<MailAcco
@ViewChild('testResultAlert', { static: false }) testResultAlert: NgbAlert
constructor(
service: MailAccountService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(MailAccountService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
}
getCreateTitle() {

View File

@ -1,11 +1,10 @@
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { first } from 'rxjs'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Correspondent } from 'src/app/data/correspondent'
@ -155,32 +154,34 @@ const METADATA_CORRESPONDENT_OPTIONS = [
],
})
export class MailRuleEditDialogComponent extends EditDialogComponent<MailRule> {
private accountService: MailAccountService
private correspondentService: CorrespondentService
private documentTypeService: DocumentTypeService
accounts: MailAccount[]
correspondents: Correspondent[]
documentTypes: DocumentType[]
constructor(
service: MailRuleService,
activeModal: NgbActiveModal,
accountService: MailAccountService,
correspondentService: CorrespondentService,
documentTypeService: DocumentTypeService,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(MailRuleService)
this.accountService = inject(MailAccountService)
this.correspondentService = inject(CorrespondentService)
this.documentTypeService = inject(DocumentTypeService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
accountService
this.accountService
.listAll()
.pipe(first())
.subscribe((result) => (this.accounts = result.results))
correspondentService
this.correspondentService
.listAll()
.pipe(first())
.subscribe((result) => (this.correspondents = result.results))
documentTypeService
this.documentTypeService
.listAll()
.pipe(first())
.subscribe((result) => (this.documentTypes = result.results))

View File

@ -64,8 +64,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
}

View File

@ -1,12 +1,12 @@
import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
import { Component, OnDestroy } from '@angular/core'
import { Component, OnDestroy, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbAccordionModule, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'
import { NgSelectComponent } from '@ng-select/ng-select'
import {
Observable,
@ -60,6 +60,8 @@ export class StoragePathEditDialogComponent
extends EditDialogComponent<StoragePath>
implements OnDestroy
{
private documentsService = inject(DocumentService)
public documentsInput$ = new Subject<string>()
public foundDocuments$: Observable<Document[]>
private testDocument: Document
@ -68,14 +70,11 @@ export class StoragePathEditDialogComponent
public loading = false
public testLoading = false
constructor(
service: StoragePathService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService,
private documentsService: DocumentService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(StoragePathService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
this.initPathObservables()
}

View File

@ -16,8 +16,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
}

View File

@ -1,11 +1,10 @@
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
import { Tag } from 'src/app/data/tag'
@ -36,13 +35,11 @@ import { TextComponent } from '../../input/text/text.component'
],
})
export class TagEditDialogComponent extends EditDialogComponent<Tag> {
constructor(
service: TagService,
activeModal: NgbActiveModal,
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(TagService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
}
getCreateTitle() {

View File

@ -1,11 +1,10 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import {
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { first } from 'rxjs'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Group } from 'src/app/data/group'
@ -37,21 +36,21 @@ export class UserEditDialogComponent
extends EditDialogComponent<User>
implements OnInit
{
private toastService = inject(ToastService)
private permissionsService = inject(PermissionsService)
private groupsService: GroupService
groups: Group[]
passwordIsSet: boolean = false
public totpLoading: boolean = false
constructor(
service: UserService,
activeModal: NgbActiveModal,
groupsService: GroupService,
settingsService: SettingsService,
private toastService: ToastService,
private permissionsService: PermissionsService
) {
super(service, activeModal, service, settingsService)
constructor() {
super()
this.service = inject(UserService)
this.groupsService = inject(GroupService)
this.settingsService = inject(SettingsService)
groupsService
this.groupsService
.listAll()
.pipe(first())
.subscribe((result) => (this.groups = result.results))

View File

@ -129,7 +129,7 @@
formControlName="schedule_offset_days"
[showAdd]="false"
[error]="error?.schedule_offset_days"
hint="Positive values will trigger the workflow before the date, negative values after."
hint="Positive values will trigger after the date, negative values before."
i18n-hint
></pngx-input-number>
</div>

View File

@ -4,7 +4,7 @@ import {
moveItemInArray,
} from '@angular/cdk/drag-drop'
import { NgTemplateOutlet } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import {
FormArray,
FormControl,
@ -12,7 +12,7 @@ import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbAccordionModule, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { first } from 'rxjs'
import { Correspondent } from 'src/app/data/correspondent'
@ -171,6 +171,12 @@ export class WorkflowEditDialogComponent
public WorkflowTriggerType = WorkflowTriggerType
public WorkflowActionType = WorkflowActionType
private correspondentService: CorrespondentService
private documentTypeService: DocumentTypeService
private storagePathService: StoragePathService
private mailRuleService: MailRuleService
private customFieldsService: CustomFieldsService
templates: Workflow[]
correspondents: Correspondent[]
documentTypes: DocumentType[]
@ -183,40 +189,38 @@ export class WorkflowEditDialogComponent
private allowedActionTypes = []
constructor(
service: WorkflowService,
activeModal: NgbActiveModal,
correspondentService: CorrespondentService,
documentTypeService: DocumentTypeService,
storagePathService: StoragePathService,
mailRuleService: MailRuleService,
userService: UserService,
settingsService: SettingsService,
customFieldsService: CustomFieldsService
) {
super(service, activeModal, userService, settingsService)
constructor() {
super()
this.service = inject(WorkflowService)
this.correspondentService = inject(CorrespondentService)
this.documentTypeService = inject(DocumentTypeService)
this.storagePathService = inject(StoragePathService)
this.mailRuleService = inject(MailRuleService)
this.userService = inject(UserService)
this.settingsService = inject(SettingsService)
this.customFieldsService = inject(CustomFieldsService)
correspondentService
this.correspondentService
.listAll()
.pipe(first())
.subscribe((result) => (this.correspondents = result.results))
documentTypeService
this.documentTypeService
.listAll()
.pipe(first())
.subscribe((result) => (this.documentTypes = result.results))
storagePathService
this.storagePathService
.listAll()
.pipe(first())
.subscribe((result) => (this.storagePaths = result.results))
mailRuleService
this.mailRuleService
.listAll()
.pipe(first())
.subscribe((result) => (this.mailRules = result.results))
customFieldsService
this.customFieldsService
.listAll()
.pipe(first())
.subscribe((result) => {

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, Input, inject } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@ -13,6 +13,10 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
imports: [FormsModule, NgxBootstrapIconsModule],
})
export class EmailDocumentDialogComponent extends LoadingComponentWithPermissions {
private activeModal = inject(NgbActiveModal)
private documentService = inject(DocumentService)
private toastService = inject(ToastService)
@Input()
title = $localize`Email Document`
@ -37,11 +41,7 @@ export class EmailDocumentDialogComponent extends LoadingComponentWithPermission
public emailSubject: string = ''
public emailMessage: string = ''
constructor(
private activeModal: NgbActiveModal,
private documentService: DocumentService,
private toastService: ToastService
) {
constructor() {
super()
this.loading = false
}

View File

@ -7,6 +7,7 @@ import {
OnInit,
Output,
ViewChild,
inject,
} from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbDropdown, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
@ -434,6 +435,9 @@ export class FilterableDropdownComponent
extends LoadingComponentWithPermissions
implements OnInit
{
private filterPipe = inject(FilterPipe)
private hotkeyService = inject(HotKeyService)
@ViewChild('listFilterTextInput') listFilterTextInput: ElementRef
@ViewChild('dropdown') dropdown: NgbDropdown
@ViewChild('buttonItems') buttonItems: ElementRef
@ -536,10 +540,7 @@ export class FilterableDropdownComponent
private keyboardIndex: number
constructor(
private filterPipe: FilterPipe,
private hotkeyService: HotKeyService
) {
constructor() {
super()
this.selectionModelChange.subscribe((updatedModel) => {
this.modelIsDirty = updatedModel.isDirty()

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
const SYMBOLS = {
@ -19,11 +19,11 @@ const SYMBOLS = {
styleUrl: './hotkey-dialog.component.scss',
})
export class HotkeyDialogComponent {
activeModal = inject(NgbActiveModal)
public title: string = $localize`Keyboard shortcuts`
public hotkeys: Map<string, string> = new Map()
constructor(public activeModal: NgbActiveModal) {}
public close(): void {
this.activeModal.close()
}

View File

@ -2,6 +2,7 @@ import {
Component,
EventEmitter,
forwardRef,
inject,
Input,
Output,
} from '@angular/core'
@ -55,7 +56,9 @@ import { UrlComponent } from '../url/url.component'
export class CustomFieldsValuesComponent extends AbstractInputComponent<Object> {
public CustomFieldDataType = CustomFieldDataType
constructor(customFieldsService: CustomFieldsService) {
constructor() {
const customFieldsService = inject(CustomFieldsService)
super()
customFieldsService.listAll().subscribe((items) => {
this.fields = items.results

View File

@ -2,6 +2,7 @@ import {
Component,
EventEmitter,
forwardRef,
inject,
Input,
OnInit,
Output,
@ -45,13 +46,9 @@ export class DateComponent
extends AbstractInputComponent<string>
implements OnInit
{
constructor(
private settings: SettingsService,
private ngbDateParserFormatter: NgbDateParserFormatter,
private isoDateAdapter: NgbDateAdapter<string>
) {
super()
}
private settings = inject(SettingsService)
private ngbDateParserFormatter = inject(NgbDateParserFormatter)
private isoDateAdapter = inject<NgbDateAdapter<string>>(NgbDateAdapter)
@Input()
suggestions: string[]

View File

@ -1,5 +1,12 @@
import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'
import {
Component,
forwardRef,
inject,
Input,
OnDestroy,
OnInit,
} from '@angular/core'
import {
FormsModule,
NG_VALUE_ACCESSOR,
@ -52,6 +59,8 @@ export class DocumentLinkComponent
extends AbstractInputComponent<any[]>
implements OnInit, OnDestroy
{
private documentsService = inject(DocumentService)
documentsInput$ = new Subject<string>()
foundDocuments$: Observable<Document[]>
loading = false
@ -75,10 +84,6 @@ export class DocumentLinkComponent
return this.selectedDocuments.map((d) => d.id)
}
constructor(private documentsService: DocumentService) {
super()
}
ngOnInit() {
this.loadDocs()
}

View File

@ -1,5 +1,6 @@
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
import { provideHttpClientTesting } from '@angular/common/http/testing'
import { LOCALE_ID } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { NG_VALUE_ACCESSOR } from '@angular/forms'
import { MonetaryComponent } from './monetary.component'
@ -41,8 +42,6 @@ describe('MonetaryComponent', () => {
it('should set the default currency code based on LOCALE_ID', () => {
expect(component.defaultCurrencyCode).toEqual('USD') // default
component = new MonetaryComponent('pt-BR')
expect(component.defaultCurrencyCode).toEqual('BRL')
})
it('should support setting a default currency code', () => {
@ -87,3 +86,28 @@ describe('MonetaryComponent', () => {
expect(component.value).toEqual('USD0.00')
})
})
describe('MonetaryComponent (Alternate Locale)', () => {
let component: MonetaryComponent
let fixture: ComponentFixture<MonetaryComponent>
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MonetaryComponent],
providers: [
{ provide: LOCALE_ID, useValue: 'pt-BR' }, // Brazilian Portuguese
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting(),
],
}).compileComponents()
fixture = TestBed.createComponent(MonetaryComponent)
fixture.debugElement.injector.get(NG_VALUE_ACCESSOR)
component = fixture.componentInstance
fixture.detectChanges()
})
it('should set the default currency code based on LOCALE_ID', () => {
expect(component.defaultCurrencyCode).toEqual('BRL')
})
})

View File

@ -1,5 +1,5 @@
import { CurrencyPipe, getLocaleCurrencyCode } from '@angular/common'
import { Component, forwardRef, Inject, Input, LOCALE_ID } from '@angular/core'
import { Component, forwardRef, inject, Input, LOCALE_ID } from '@angular/core'
import {
FormsModule,
NG_VALUE_ACCESSOR,
@ -27,6 +27,8 @@ import { AbstractInputComponent } from '../abstract-input'
],
})
export class MonetaryComponent extends AbstractInputComponent<string> {
currentLocale = inject(LOCALE_ID)
public currency: string = ''
public _monetaryValue: string = ''
@ -45,11 +47,10 @@ export class MonetaryComponent extends AbstractInputComponent<string> {
if (currency) this.defaultCurrencyCode = currency
}
constructor(@Inject(LOCALE_ID) currentLocale: string) {
constructor() {
super()
this.currency = this.defaultCurrencyCode =
this.defaultCurrency ?? getLocaleCurrencyCode(currentLocale)
this.defaultCurrency ?? getLocaleCurrencyCode(this.currentLocale)
}
writeValue(newValue: any): void {

View File

@ -1,4 +1,4 @@
import { Component, forwardRef, Input } from '@angular/core'
import { Component, forwardRef, inject, Input } from '@angular/core'
import {
FormsModule,
NG_VALUE_ACCESSOR,
@ -22,16 +22,14 @@ import { AbstractInputComponent } from '../abstract-input'
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
})
export class NumberComponent extends AbstractInputComponent<number> {
private documentService = inject(DocumentService)
@Input()
showAdd: boolean = true
@Input()
step: number = 1
constructor(private documentService: DocumentService) {
super()
}
nextAsn() {
if (this.value) {
return

View File

@ -1,4 +1,4 @@
import { Component, forwardRef } from '@angular/core'
import { Component, forwardRef, inject } from '@angular/core'
import {
FormsModule,
NG_VALUE_ACCESSOR,
@ -26,7 +26,9 @@ import { AbstractInputComponent } from '../../abstract-input'
export class PermissionsGroupComponent extends AbstractInputComponent<Group> {
groups: Group[]
constructor(groupService: GroupService) {
constructor() {
const groupService = inject(GroupService)
super()
groupService
.listAll()

View File

@ -1,4 +1,4 @@
import { Component, forwardRef } from '@angular/core'
import { Component, forwardRef, inject } from '@angular/core'
import {
FormsModule,
NG_VALUE_ACCESSOR,
@ -8,7 +8,6 @@ import { NgSelectComponent } from '@ng-select/ng-select'
import { first } from 'rxjs/operators'
import { User } from 'src/app/data/user'
import { UserService } from 'src/app/services/rest/user.service'
import { SettingsService } from 'src/app/services/settings.service'
import { AbstractInputComponent } from '../../abstract-input'
@Component({
@ -27,7 +26,9 @@ import { AbstractInputComponent } from '../../abstract-input'
export class PermissionsUserComponent extends AbstractInputComponent<User[]> {
users: User[]
constructor(userService: UserService, settings: SettingsService) {
constructor() {
const userService = inject(UserService)
super()
userService
.listAll()

View File

@ -2,6 +2,7 @@ import {
Component,
EventEmitter,
forwardRef,
inject,
Input,
OnInit,
Output,
@ -45,10 +46,10 @@ import { TagComponent } from '../../tag/tag.component'
],
})
export class TagsComponent implements OnInit, ControlValueAccessor {
constructor(
private tagService: TagService,
private modalService: NgbModal
) {
private tagService = inject(TagService)
private modalService = inject(NgbModal)
constructor() {
this.createTagRef = this.createTag.bind(this)
}

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, Input, inject } from '@angular/core'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { SettingsService } from 'src/app/services/settings.service'
import { environment } from 'src/environments/environment'
@ -9,6 +9,8 @@ import { environment } from 'src/environments/environment'
styleUrls: ['./logo.component.scss'],
})
export class LogoComponent {
private settingsService = inject(SettingsService)
@Input()
extra_classes: string
@ -24,8 +26,6 @@ export class LogoComponent {
: null
}
constructor(private settingsService: SettingsService) {}
getClasses() {
return ['logo'].concat(this.extra_classes).join(' ')
}

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, Input, inject } from '@angular/core'
import { Title } from '@angular/platform-browser'
import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@ -12,7 +12,7 @@ import { environment } from 'src/environments/environment'
imports: [NgbPopoverModule, NgxBootstrapIconsModule, TourNgBootstrapModule],
})
export class PageHeaderComponent {
constructor(private titleService: Title) {}
private titleService = inject(Title)
_title = ''

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'
import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import {
FormControl,
FormGroup,
@ -24,13 +24,13 @@ import { SwitchComponent } from '../input/switch/switch.component'
],
})
export class PermissionsDialogComponent {
activeModal = inject(NgbActiveModal)
private userService = inject(UserService)
users: User[]
private o: ObjectWithPermissions = undefined
constructor(
public activeModal: NgbActiveModal,
private userService: UserService
) {
constructor() {
this.userService.listAll().subscribe((r) => (this.users = r.results))
}

View File

@ -1,5 +1,5 @@
import { NgClass } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core'
import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
import { NgSelectComponent } from '@ng-select/ng-select'
@ -58,6 +58,9 @@ export enum OwnerFilterType {
],
})
export class PermissionsFilterDropdownComponent extends ComponentWithPermissions {
permissionsService = inject(PermissionsService)
private settingsService = inject(SettingsService)
public OwnerFilterType = OwnerFilterType
@Input()
@ -83,12 +86,12 @@ export class PermissionsFilterDropdownComponent extends ComponentWithPermissions
)
}
constructor(
public permissionsService: PermissionsService,
userService: UserService,
private settingsService: SettingsService
) {
constructor() {
const userService = inject(UserService)
super()
const permissionsService = this.permissionsService
if (
permissionsService.currentUserCan(
PermissionAction.View,

View File

@ -1,5 +1,5 @@
import { KeyValuePipe } from '@angular/common'
import { Component, forwardRef, Input, OnInit } from '@angular/core'
import { Component, forwardRef, inject, Input, OnInit } from '@angular/core'
import {
AbstractControl,
ControlValueAccessor,
@ -43,6 +43,9 @@ export class PermissionsSelectComponent
extends ComponentWithPermissions
implements OnInit, ControlValueAccessor
{
private readonly permissionsService = inject(PermissionsService)
private readonly settingsService = inject(SettingsService)
@Input()
title: string = 'Permissions'
@ -76,10 +79,7 @@ export class PermissionsSelectComponent
public allowedTypes = Object.keys(PermissionType)
constructor(
private readonly permissionsService: PermissionsService,
private readonly settingsService: SettingsService
) {
constructor() {
super()
if (!this.settingsService.get(SETTINGS_KEYS.AUDITLOG_ENABLED)) {
this.allowedTypes.splice(this.allowedTypes.indexOf('History'), 1)

View File

@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http'
import { Component, Input, OnDestroy, ViewChild } from '@angular/core'
import { Component, inject, Input, OnDestroy, ViewChild } from '@angular/core'
import { NgbPopover, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import { PdfViewerComponent, PdfViewerModule } from 'ng2-pdf-viewer'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@ -24,6 +24,10 @@ import { SettingsService } from 'src/app/services/settings.service'
],
})
export class PreviewPopupComponent implements OnDestroy {
private settingsService = inject(SettingsService)
private documentService = inject(DocumentService)
private http = inject(HttpClient)
private _document: Document
@Input()
set document(document: Document) {
@ -82,12 +86,6 @@ export class PreviewPopupComponent implements OnDestroy {
)
}
constructor(
private settingsService: SettingsService,
private documentService: DocumentService,
private http: HttpClient
) {}
ngOnDestroy(): void {
this.unsubscribeNotifier.next(this)
}

View File

@ -1,5 +1,5 @@
import { Clipboard } from '@angular/cdk/clipboard'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import {
FormControl,
FormGroup,
@ -46,6 +46,11 @@ export class ProfileEditDialogComponent
extends LoadingComponentWithPermissions
implements OnInit
{
private profileService = inject(ProfileService)
activeModal = inject(NgbActiveModal)
private toastService = inject(ToastService)
private clipboard = inject(Clipboard)
public networkActive: boolean = false
public error: any
@ -83,15 +88,6 @@ export class ProfileEditDialogComponent
public socialAccounts: SocialAccount[] = []
public socialAccountProviders: SocialAccountProvider[] = []
constructor(
private profileService: ProfileService,
public activeModal: NgbActiveModal,
private toastService: ToastService,
private clipboard: Clipboard
) {
super()
}
ngOnInit(): void {
this.networkActive = true
this.profileService

View File

@ -10,6 +10,7 @@ import {
fakeAsync,
tick,
} from '@angular/core/testing'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { By } from '@angular/platform-browser'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
@ -33,6 +34,8 @@ describe('ShareLinksDialogComponent', () => {
imports: [
ShareLinksDialogComponent,
NgxBootstrapIconsModule.pick(allIcons),
FormsModule,
ReactiveFormsModule,
],
providers: [
provideHttpClient(withInterceptorsFromDi()),
@ -223,16 +226,18 @@ describe('ShareLinksDialogComponent', () => {
)
})
it('should disable archive switch & option if no archive available', () => {
it('should disable archive switch & option if no archive available', (done) => {
component.hasArchiveVersion = false
component.ngOnInit()
fixture.detectChanges()
expect(component.useArchiveVersion).toBeFalsy()
expect(
fixture.debugElement.query(By.css("input[type='checkbox']")).attributes[
'ng-reflect-is-disabled'
]
).toBeTruthy()
setTimeout(() => {
// some stupid change detection issue
const inputEl = fixture.debugElement.query(By.css('#versionSwitch'))
.nativeElement as HTMLInputElement
expect(inputEl.disabled).toBeTruthy()
done()
})
})
it('should support close', () => {

View File

@ -1,5 +1,5 @@
import { Clipboard } from '@angular/cdk/clipboard'
import { Component, Input, OnInit } from '@angular/core'
import { Component, Input, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@ -16,6 +16,11 @@ import { environment } from 'src/environments/environment'
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
})
export class ShareLinksDialogComponent implements OnInit {
private activeModal = inject(NgbActiveModal)
private shareLinkService = inject(ShareLinkService)
private toastService = inject(ToastService)
private clipboard = inject(Clipboard)
EXPIRATION_OPTIONS = [
{ label: $localize`1 day`, value: 1 },
{ label: $localize`7 days`, value: 7 },
@ -58,13 +63,6 @@ export class ShareLinksDialogComponent implements OnInit {
useArchiveVersion: boolean = true
constructor(
private activeModal: NgbActiveModal,
private shareLinkService: ShareLinkService,
private toastService: ToastService,
private clipboard: Clipboard
) {}
ngOnInit(): void {
if (this._documentId !== undefined) this.refresh()
}

View File

@ -20,7 +20,18 @@
<div class="card-body">
<dl class="card-text">
<dt i18n>Paperless-ngx Version</dt>
<dd>{{status.pngx_version}}</dd>
<dd>
{{status.pngx_version}}
@if (versionMismatch) {
<button class="btn btn-sm d-inline align-items-center btn-dark text-uppercase small" [ngbPopover]="versionPopover" triggers="click mouseenter:mouseleave">
<i-bs name="exclamation-triangle-fill" class="text-danger lh-1"></i-bs>
</button>
}
<ng-template #versionPopover>
Frontend version: {{frontendVersion}}<br>
Backend version: {{status.pngx_version}}
</ng-template>
</dd>
<dt i18n>Install Type</dt>
<dd>{{status.install_type}}</dd>
<dt i18n>Server OS</dt>

View File

@ -1,3 +1,18 @@
// Mock production environment for testing
jest.mock('src/environments/environment', () => ({
environment: {
production: true,
apiBaseUrl: 'http://localhost:8000/api/',
apiVersion: '9',
appTitle: 'Paperless-ngx',
tag: 'prod',
version: '2.4.3',
webSocketHost: 'localhost:8000',
webSocketProtocol: 'ws:',
webSocketBaseUrl: '/ws/',
},
}))
import { Clipboard } from '@angular/cdk/clipboard'
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
import { provideHttpClientTesting } from '@angular/common/http/testing'
@ -142,4 +157,15 @@ describe('SystemStatusDialogComponent', () => {
`Task ${PaperlessTaskName.IndexOptimize} started`
)
})
it('shoduld handle version mismatch', () => {
component.frontendVersion = '2.4.2'
component.ngOnInit()
expect(component.versionMismatch).toBeTruthy()
expect(component.status.pngx_version).toContain('(frontend: 2.4.2)')
component.frontendVersion = '2.4.3'
component.status.pngx_version = '2.4.3'
component.ngOnInit()
expect(component.versionMismatch).toBeFalsy()
})
})

View File

@ -1,5 +1,5 @@
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'
import { Component } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import {
NgbActiveModal,
NgbModalModule,
@ -18,6 +18,7 @@ import { PermissionsService } from 'src/app/services/permissions.service'
import { SystemStatusService } from 'src/app/services/system-status.service'
import { TasksService } from 'src/app/services/tasks.service'
import { ToastService } from 'src/app/services/toast.service'
import { environment } from 'src/environments/environment'
@Component({
selector: 'pngx-system-status-dialog',
@ -33,10 +34,19 @@ import { ToastService } from 'src/app/services/toast.service'
NgxBootstrapIconsModule,
],
})
export class SystemStatusDialogComponent {
export class SystemStatusDialogComponent implements OnInit {
activeModal = inject(NgbActiveModal)
private clipboard = inject(Clipboard)
private systemStatusService = inject(SystemStatusService)
private tasksService = inject(TasksService)
private toastService = inject(ToastService)
private permissionsService = inject(PermissionsService)
public SystemStatusItemStatus = SystemStatusItemStatus
public PaperlessTaskName = PaperlessTaskName
public status: SystemStatus
public frontendVersion: string = environment.version
public versionMismatch: boolean = false
public copied: boolean = false
@ -46,14 +56,16 @@ export class SystemStatusDialogComponent {
return this.permissionsService.isSuperUser()
}
constructor(
public activeModal: NgbActiveModal,
private clipboard: Clipboard,
private systemStatusService: SystemStatusService,
private tasksService: TasksService,
private toastService: ToastService,
private permissionsService: PermissionsService
) {}
public ngOnInit() {
this.versionMismatch =
environment.production &&
this.status.pngx_version &&
this.frontendVersion &&
this.status.pngx_version !== this.frontendVersion
if (this.versionMismatch) {
this.status.pngx_version = `${this.status.pngx_version} (frontend: ${this.frontendVersion})`
}
}
public close() {
this.activeModal.close()

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, inject, Input } from '@angular/core'
import { Tag } from 'src/app/data/tag'
import {
PermissionAction,
@ -13,14 +13,12 @@ import { TagService } from 'src/app/services/rest/tag.service'
styleUrls: ['./tag.component.scss'],
})
export class TagComponent {
private permissionsService = inject(PermissionsService)
private tagService = inject(TagService)
private _tag: Tag
private _tagID: number
constructor(
private permissionsService: PermissionsService,
private tagService: TagService
) {}
@Input()
public set tag(tag: Tag) {
this._tag = tag

View File

@ -1,6 +1,6 @@
import { Clipboard } from '@angular/cdk/clipboard'
import { DecimalPipe } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core'
import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import {
NgbProgressbarModule,
NgbToastModule,
@ -21,6 +21,8 @@ import { Toast } from 'src/app/services/toast.service'
styleUrl: './toast.component.scss',
})
export class ToastComponent {
private clipboard = inject(Clipboard)
@Input() toast: Toast
@Input() autohide: boolean = true
@ -31,8 +33,6 @@ export class ToastComponent {
public copied: boolean = false
constructor(private clipboard: Clipboard) {}
onShown(toast: Toast) {
if (!this.autohide) return

View File

@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import {
NgbAccordionModule,
NgbProgressbarModule,
@ -20,7 +20,7 @@ import { ToastComponent } from '../toast/toast.component'
],
})
export class ToastsComponent implements OnInit, OnDestroy {
constructor(public toastService: ToastService) {}
toastService = inject(ToastService)
private subscription: Subscription

View File

@ -5,7 +5,7 @@ import {
DragDropModule,
moveItemInArray,
} from '@angular/cdk/drag-drop'
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import { RouterModule } from '@angular/router'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap'
@ -42,13 +42,13 @@ import { WelcomeWidgetComponent } from './widgets/welcome-widget/welcome-widget.
],
})
export class DashboardComponent extends ComponentWithPermissions {
settingsService = inject(SettingsService)
savedViewService = inject(SavedViewService)
private tourService = inject(TourService)
private toastService = inject(ToastService)
public dashboardViews: SavedView[] = []
constructor(
public settingsService: SettingsService,
public savedViewService: SavedViewService,
private tourService: TourService,
private toastService: ToastService
) {
constructor() {
super()
this.savedViewService.listAll().subscribe(() => {

View File

@ -1,6 +1,7 @@
import { AsyncPipe, NgClass, NgStyle } from '@angular/common'
import {
Component,
inject,
Input,
OnDestroy,
OnInit,
@ -84,26 +85,22 @@ export class SavedViewWidgetComponent
extends LoadingComponentWithPermissions
implements OnInit, OnDestroy
{
private documentService = inject(DocumentService)
private router = inject(Router)
private list = inject(DocumentListViewService)
private websocketStatusService = inject(WebsocketStatusService)
openDocumentsService = inject(OpenDocumentsService)
documentListViewService = inject(DocumentListViewService)
permissionsService = inject(PermissionsService)
private settingsService = inject(SettingsService)
private customFieldService = inject(CustomFieldsService)
public DisplayMode = DisplayMode
public DisplayField = DisplayField
public CustomFieldDataType = CustomFieldDataType
private customFields: CustomField[] = []
constructor(
private documentService: DocumentService,
private router: Router,
private list: DocumentListViewService,
private websocketStatusService: WebsocketStatusService,
public openDocumentsService: OpenDocumentsService,
public documentListViewService: DocumentListViewService,
public permissionsService: PermissionsService,
private settingsService: SettingsService,
private customFieldService: CustomFieldsService
) {
super()
}
@Input()
savedView: SavedView

View File

@ -1,6 +1,6 @@
import { DecimalPipe } from '@angular/common'
import { HttpClient } from '@angular/common/http'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, inject, OnDestroy, OnInit } from '@angular/core'
import { RouterModule } from '@angular/router'
import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import * as mimeTypeNames from 'mime-names'
@ -51,15 +51,11 @@ export class StatisticsWidgetComponent
extends ComponentWithPermissions
implements OnInit, OnDestroy
{
loading: boolean = false
private http = inject(HttpClient)
private websocketConnectionService = inject(WebsocketStatusService)
private documentListViewService = inject(DocumentListViewService)
constructor(
private http: HttpClient,
private websocketConnectionService: WebsocketStatusService,
private documentListViewService: DocumentListViewService
) {
super()
}
loading: boolean = false
statistics: Statistics = {}

View File

@ -1,5 +1,5 @@
import { NgClass, NgTemplateOutlet } from '@angular/common'
import { Component, QueryList, ViewChildren } from '@angular/core'
import { Component, QueryList, ViewChildren, inject } from '@angular/core'
import { RouterModule } from '@angular/router'
import {
NgbAlert,
@ -37,15 +37,11 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component'
],
})
export class UploadFileWidgetComponent extends ComponentWithPermissions {
@ViewChildren(NgbAlert) alerts: QueryList<NgbAlert>
private websocketStatusService = inject(WebsocketStatusService)
private uploadDocumentsService = inject(UploadDocumentsService)
settingsService = inject(SettingsService)
constructor(
private websocketStatusService: WebsocketStatusService,
private uploadDocumentsService: UploadDocumentsService,
public settingsService: SettingsService
) {
super()
}
@ViewChildren(NgbAlert) alerts: QueryList<NgbAlert>
getStatus() {
return this.websocketStatusService.getConsumerStatus()

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Output } from '@angular/core'
import { Component, EventEmitter, Output, inject } from '@angular/core'
import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'
import { TourService } from 'ngx-ui-tour-ng-bootstrap'
@ -9,7 +9,7 @@ import { TourService } from 'ngx-ui-tour-ng-bootstrap'
imports: [NgbAlertModule],
})
export class WelcomeWidgetComponent {
constructor(public readonly tourService: TourService) {}
readonly tourService = inject(TourService)
@Output()
dismiss: EventEmitter<boolean> = new EventEmitter()

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { FILTER_ASN } from '../../data/filter-rule-type'
import { DocumentService } from '../../services/rest/document.service'
@ -9,12 +9,11 @@ import { DocumentService } from '../../services/rest/document.service'
styleUrls: ['./document-asn.component.scss'],
})
export class DocumentAsnComponent implements OnInit {
private documentsService = inject(DocumentService)
private route = inject(ActivatedRoute)
private router = inject(Router)
asn: string
constructor(
private documentsService: DocumentService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit(): void {
this.route.paramMap.subscribe((paramMap) => {

View File

@ -1,6 +1,6 @@
import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
import { HttpClient, HttpResponse } from '@angular/common/http'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { Component, inject, OnDestroy, OnInit, ViewChild } from '@angular/core'
import {
FormArray,
FormControl,
@ -176,6 +176,26 @@ export class DocumentDetailComponent
extends ComponentWithPermissions
implements OnInit, OnDestroy, DirtyComponent
{
private documentsService = inject(DocumentService)
private route = inject(ActivatedRoute)
private correspondentService = inject(CorrespondentService)
private documentTypeService = inject(DocumentTypeService)
private router = inject(Router)
private modalService = inject(NgbModal)
private openDocumentService = inject(OpenDocumentsService)
private documentListViewService = inject(DocumentListViewService)
private documentTitlePipe = inject(DocumentTitlePipe)
private toastService = inject(ToastService)
private settings = inject(SettingsService)
private storagePathService = inject(StoragePathService)
private permissionsService = inject(PermissionsService)
private userService = inject(UserService)
private customFieldsService = inject(CustomFieldsService)
private http = inject(HttpClient)
private hotKeyService = inject(HotKeyService)
private componentRouterService = inject(ComponentRouterService)
private deviceDetectorService = inject(DeviceDetectorService)
@ViewChild('inputTitle')
titleInput: TextComponent
@ -259,30 +279,6 @@ export class DocumentDetailComponent
DocumentDetailNavIDs = DocumentDetailNavIDs
activeNavID: number
constructor(
private documentsService: DocumentService,
private route: ActivatedRoute,
private correspondentService: CorrespondentService,
private documentTypeService: DocumentTypeService,
private router: Router,
private modalService: NgbModal,
private openDocumentService: OpenDocumentsService,
private documentListViewService: DocumentListViewService,
private documentTitlePipe: DocumentTitlePipe,
private toastService: ToastService,
private settings: SettingsService,
private storagePathService: StoragePathService,
private permissionsService: PermissionsService,
private userService: UserService,
private customFieldsService: CustomFieldsService,
private http: HttpClient,
private hotKeyService: HotKeyService,
private componentRouterService: ComponentRouterService,
private deviceDetectorService: DeviceDetectorService
) {
super()
}
titleKeyUp(event) {
this.titleSubject.next(event.target?.value)
}

View File

@ -1,5 +1,5 @@
import { AsyncPipe, KeyValuePipe, TitleCasePipe } from '@angular/common'
import { Component, Input, OnInit } from '@angular/core'
import { Component, Input, OnInit, inject } from '@angular/core'
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Observable, first, map, of } from 'rxjs'
@ -26,6 +26,12 @@ import { UserService } from 'src/app/services/rest/user.service'
],
})
export class DocumentHistoryComponent implements OnInit {
private documentService = inject(DocumentService)
private correspondentService = inject(CorrespondentService)
private storagePathService = inject(StoragePathService)
private documentTypeService = inject(DocumentTypeService)
private userService = inject(UserService)
public AuditLogAction = AuditLogAction
private _documentId: number
@ -38,14 +44,6 @@ export class DocumentHistoryComponent implements OnInit {
public loading: boolean = true
public entries: AuditLogEntry[] = []
constructor(
private documentService: DocumentService,
private correspondentService: CorrespondentService,
private storagePathService: StoragePathService,
private documentTypeService: DocumentTypeService,
private userService: UserService
) {}
ngOnInit(): void {
if (this._documentId) {
this.loading = true

View File

@ -1,4 +1,4 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core'
import { Component, inject, Input, OnDestroy, OnInit } from '@angular/core'
import {
FormControl,
FormGroup,
@ -71,6 +71,19 @@ export class BulkEditorComponent
extends ComponentWithPermissions
implements OnInit, OnDestroy
{
private documentTypeService = inject(DocumentTypeService)
private tagService = inject(TagService)
private correspondentService = inject(CorrespondentService)
list = inject(DocumentListViewService)
private documentService = inject(DocumentService)
private modalService = inject(NgbModal)
private openDocumentService = inject(OpenDocumentsService)
private settings = inject(SettingsService)
private toastService = inject(ToastService)
private storagePathService = inject(StoragePathService)
private customFieldService = inject(CustomFieldsService)
private permissionService = inject(PermissionsService)
tagSelectionModel = new FilterableDropdownSelectionModel(true)
correspondentSelectionModel = new FilterableDropdownSelectionModel()
documentTypeSelectionModel = new FilterableDropdownSelectionModel()
@ -94,23 +107,6 @@ export class BulkEditorComponent
@Input()
public disabled: boolean = false
constructor(
private documentTypeService: DocumentTypeService,
private tagService: TagService,
private correspondentService: CorrespondentService,
public list: DocumentListViewService,
private documentService: DocumentService,
private modalService: NgbModal,
private openDocumentService: OpenDocumentsService,
private settings: SettingsService,
private toastService: ToastService,
private storagePathService: StoragePathService,
private customFieldService: CustomFieldsService,
private permissionService: PermissionsService
) {
super()
}
applyOnClose: boolean = this.settings.get(
SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE
)

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Output } from '@angular/core'
import { Component, EventEmitter, Output, inject } from '@angular/core'
import {
FormControl,
FormGroup,
@ -38,6 +38,9 @@ import { DocumentService } from 'src/app/services/rest/document.service'
],
})
export class CustomFieldsBulkEditDialogComponent {
private activeModal = inject(NgbActiveModal)
private documentService = inject(DocumentService)
CustomFieldDataType = CustomFieldDataType
@Output()
@ -73,11 +76,6 @@ export class CustomFieldsBulkEditDialogComponent {
public documents: number[] = []
constructor(
private activeModal: NgbActiveModal,
private documentService: DocumentService
) {}
initForm() {
Object.keys(this.form.controls).forEach((key) => {
if (!this._fieldsToAddIds.includes(parseInt(key))) {

View File

@ -6,6 +6,7 @@ import {
Input,
Output,
ViewChild,
inject,
} from '@angular/core'
import { RouterModule } from '@angular/router'
import {
@ -62,14 +63,10 @@ export class DocumentCardLargeComponent
extends LoadingComponentWithPermissions
implements AfterViewInit
{
DisplayField = DisplayField
private documentService = inject(DocumentService)
settingsService = inject(SettingsService)
constructor(
private documentService: DocumentService,
public settingsService: SettingsService
) {
super()
}
DisplayField = DisplayField
@Input()
selected = false

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