Compare commits

..

68 Commits

Author SHA1 Message Date
shamoon
9eb81d5458 Merge branch 'dev' into feature-remote-ocr-2 2025-12-07 20:37:56 -08:00
dependabot[bot]
963a519e5c Chore(deps-dev): Bump webpack from 5.102.1 to 5.103.0 in /src-ui (#11513)
Bumps [webpack](https://github.com/webpack/webpack) from 5.102.1 to 5.103.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.102.1...v5.103.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.103.0
  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-12-08 04:08:40 +00:00
dependabot[bot]
59e5d15cf0 Chore(deps-dev): Bump @playwright/test from 1.56.1 to 1.57.0 in /src-ui (#11514)
Bumps [@playwright/test](https://github.com/microsoft/playwright) from 1.56.1 to 1.57.0.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.56.1...v1.57.0)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-version: 1.57.0
  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-12-08 03:54:27 +00:00
GitHub Actions
ef2f65fcb8 Auto translate strings 2025-12-08 03:09:28 +00:00
shamoon
555ba8bb19 Chore: remove use of logs ngFor 2025-12-07 19:07:28 -08:00
dependabot[bot]
01992bb5c6 Chore(deps-dev): Bump the frontend-eslint-dependencies group (#11512)
Bumps the frontend-eslint-dependencies group in /src-ui with 3 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [@typescript-eslint/utils](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/utils).


Updates `@typescript-eslint/eslint-plugin` from 8.47.0 to 8.48.0
- [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.48.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.47.0 to 8.48.0
- [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.48.0/packages/parser)

Updates `@typescript-eslint/utils` from 8.47.0 to 8.48.0
- [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.48.0/packages/utils)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.48.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-eslint-dependencies
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.48.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-eslint-dependencies
- dependency-name: "@typescript-eslint/utils"
  dependency-version: 8.48.0
  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-12-08 03:05:46 +00:00
shamoon
6a5ea49715 Merge branch 'dev' into feature-remote-ocr-2 2025-11-22 13:18:50 -08:00
shamoon
7d2fe630a5 Merge branch 'dev' into feature-remote-ocr-2 2025-11-19 23:49:11 -08:00
shamoon
c29dd5485b Merge branch 'dev' into feature-remote-ocr-2 2025-11-18 12:08:38 -08:00
shamoon
cef100a955 Wrap in try/catch 2025-11-18 12:07:16 -08:00
shamoon
4f53d1b6ee Merge branch 'dev' into feature-remote-ocr-2 2025-11-17 20:54:37 -08:00
shamoon
23cea77548 Merge branch 'dev' into feature-remote-ocr-2 2025-11-17 18:49:01 -08:00
shamoon
4900af93c6 Merge branch 'dev' into feature-remote-ocr-2 2025-11-15 13:49:39 -08:00
shamoon
ef834ae808 Merge branch 'dev' into feature-remote-ocr-2 2025-11-13 15:45:08 -08:00
shamoon
0537e87cb5 Merge branch 'dev' into feature-remote-ocr-2 2025-11-06 11:46:02 -08:00
shamoon
b4da5c3cd1 Merge branch 'dev' into feature-remote-ocr-2 2025-11-04 16:24:26 -08:00
shamoon
251b0fb3d6 Merge branch 'dev' into feature-remote-ocr-2 2025-11-04 08:24:02 -08:00
shamoon
32bdf11f7f Merge branch 'dev' into feature-remote-ocr-2 2025-11-02 08:14:04 -08:00
shamoon
0627ca69f5 Merge branch 'dev' into feature-remote-ocr-2 2025-10-29 11:13:53 -07:00
shamoon
f5525bbdff Merge branch 'dev' into feature-remote-ocr-2 2025-10-27 21:22:42 -07:00
shamoon
a21a2a41a8 Merge branch 'dev' into feature-remote-ocr-2 2025-10-26 07:41:51 -07:00
shamoon
cc73ed8b86 Merge branch 'dev' into feature-remote-ocr-2 2025-10-24 16:48:07 -07:00
shamoon
0c706b2316 Merge branch 'dev' into feature-remote-ocr-2 2025-10-23 16:38:35 -07:00
shamoon
85b7b6874d Merge branch 'dev' into feature-remote-ocr-2 2025-10-22 21:53:07 -07:00
shamoon
56b26185fa Merge branch 'dev' into feature-remote-ocr-2 2025-10-21 08:23:20 -07:00
shamoon
6537fade7b Merge branch 'dev' into feature-remote-ocr-2 2025-10-15 16:04:02 -07:00
shamoon
9f8090816f Merge branch 'dev' into feature-remote-ocr-2 2025-10-09 12:54:58 -07:00
shamoon
1de7c52478 Merge branch 'dev' into feature-remote-ocr-2 2025-10-01 19:24:38 -07:00
shamoon
9aaaa6f069 Merge branch 'dev' into feature-remote-ocr-2 2025-09-30 09:14:56 -07:00
shamoon
c3a20b7797 Merge branch 'dev' into feature-remote-ocr-2 2025-09-28 15:06:37 -07:00
shamoon
476556379b Merge branch 'dev' into feature-remote-ocr-2 2025-09-24 13:46:49 -07:00
shamoon
e5cafff043 Merge branch 'dev' into feature-remote-ocr-2 2025-09-22 13:42:55 -07:00
shamoon
8e0d574e99 Merge branch 'dev' into feature-remote-ocr-2 2025-09-21 16:18:13 -07:00
shamoon
8a5820328e Sonar suggestions 2025-09-17 19:18:47 -07:00
shamoon
809d62a2f4 Merge branch 'dev' into feature-remote-ocr-2 2025-09-17 16:51:23 -07:00
shamoon
0d87f94b9b Merge branch 'dev' into feature-remote-ocr-2 2025-09-14 14:01:35 -07:00
shamoon
315b90f8e5 Add typing to assertContainsStrings test util 2025-09-11 13:56:14 -07:00
shamoon
47b2d2964b Use regular testcase instead of django, config check test 2025-09-11 13:52:10 -07:00
shamoon
e05639ae4e tempdir already a path 2025-09-11 13:49:30 -07:00
shamoon
f400a8cb2f Close client 2025-09-11 13:49:06 -07:00
shamoon
26abcf5612 Also ensure API key is set 2025-09-11 13:48:06 -07:00
shamoon
afde52430d Merge branch 'dev' into feature-remote-ocr-2 2025-09-11 13:25:53 -07:00
shamoon
716f2da652 Merge branch 'dev' into feature-remote-ocr-2 2025-09-08 11:36:49 -07:00
shamoon
c54073b7c2 Merge branch 'dev' into feature-remote-ocr-2 2025-09-04 09:16:59 -07:00
shamoon
247e6f39dc Merge branch 'dev' into feature-remote-ocr-2 2025-09-01 20:10:40 -07:00
shamoon
1e6dfc4481 Merge branch 'dev' into feature-remote-ocr-2 2025-08-26 13:30:39 -07:00
shamoon
7cc0750066 Add note on costs and limitations for Azure OCR 2025-08-24 05:47:07 -07:00
shamoon
bd6585d3b4 Merge branch 'dev' into feature-remote-ocr-2 2025-08-22 08:54:26 -07:00
shamoon
717e828a1d Merge branch 'dev' into feature-remote-ocr-2 2025-08-17 21:25:14 -07:00
shamoon
07381d48e6 Merge branch 'dev' into feature-remote-ocr-2 2025-08-17 07:49:58 -07:00
shamoon
dd0ffaf312 Merge branch 'dev' into feature-remote-ocr-2 2025-08-11 10:48:36 -07:00
shamoon
264504affc Fix consumer declaration file extensions 2025-08-10 05:32:52 -07:00
shamoon
4feedf2add Merge branch 'dev' into feature-remote-ocr-2 2025-08-06 16:04:25 -04:00
shamoon
2f76cf9831 Merge branch 'dev' into feature-remote-ocr-2 2025-08-01 23:55:49 -04:00
shamoon
1002d37f6b Update test_parser.py 2025-07-09 11:05:37 -07:00
shamoon
d260a94740 Update parsers.py 2025-07-09 11:02:57 -07:00
shamoon
88c69b83ea Update index.md 2025-07-09 11:00:12 -07:00
shamoon
2557ee2014 Update docs to mention remote OCR with Azure AI 2025-07-09 09:53:30 -07:00
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
36 changed files with 661 additions and 211 deletions

View File

@@ -1794,3 +1794,23 @@ password. All of these options come from their similarly-named [Django settings]
#### [`PAPERLESS_EMAIL_USE_SSL=<bool>`](#PAPERLESS_EMAIL_USE_SSL) {#PAPERLESS_EMAIL_USE_SSL}
: Defaults to false.
## Remote OCR
#### [`PAPERLESS_REMOTE_OCR_ENGINE=<str>`](#PAPERLESS_REMOTE_OCR_ENGINE) {#PAPERLESS_REMOTE_OCR_ENGINE}
: The remote OCR engine to use. Currently only Azure AI is supported as "azureai".
Defaults to None, which disables remote OCR.
#### [`PAPERLESS_REMOTE_OCR_API_KEY=<str>`](#PAPERLESS_REMOTE_OCR_API_KEY) {#PAPERLESS_REMOTE_OCR_API_KEY}
: The API key to use for the remote OCR engine.
Defaults to None.
#### [`PAPERLESS_REMOTE_OCR_ENDPOINT=<str>`](#PAPERLESS_REMOTE_OCR_ENDPOINT) {#PAPERLESS_REMOTE_OCR_ENDPOINT}
: The endpoint to use for the remote OCR engine. This is required for Azure AI.
Defaults to None.

View File

@@ -25,9 +25,10 @@ physical documents into a searchable online archive so you can keep, well, _less
## Features
- **Organize and index** your scanned documents with tags, correspondents, types, and more.
- _Your_ data is stored locally on _your_ server and is never transmitted or shared in any way.
- _Your_ data is stored locally on _your_ server and is never transmitted or shared in any way, unless you explicitly choose to do so.
- Performs **OCR** on your documents, adding searchable and selectable text, even to documents scanned with only images.
- Utilizes the open-source Tesseract engine to recognize more than 100 languages.
- Utilizes the open-source Tesseract engine to recognize more than 100 languages.
- _New!_ Supports remote OCR with Azure AI (opt-in).
- Documents are saved as PDF/A format which is designed for long term storage, alongside the unaltered originals.
- Uses machine-learning to automatically add tags, correspondents and document types to your documents.
- Supports PDF documents, images, plain text files, Office documents (Word, Excel, PowerPoint, and LibreOffice equivalents)[^1] and more.

View File

@@ -892,6 +892,21 @@ how regularly you intend to scan documents and use paperless.
performed the task associated with the document, move it to the
inbox.
## Remote OCR
!!! important
This feature is disabled by default and will always remain strictly "opt-in".
Paperless-ngx supports performing OCR on documents using remote services. At the moment, this is limited to
[Microsoft's Azure "Document Intelligence" service](https://azure.microsoft.com/en-us/products/ai-services/ai-document-intelligence).
This is of course a paid service (with a free tier) which requires an Azure account and subscription. Azure AI is not affiliated with
Paperless-ngx in any way. When enabled, Paperless-ngx will automatically send appropriate documents to Azure for OCR processing, bypassing
the local OCR engine. See the [configuration](configuration.md#PAPERLESS_REMOTE_OCR_ENGINE) options for more details.
Additionally, when using a commercial service with this feature, consider both potential costs as well as any associated file size
or page limitations (e.g. with a free tier).
## Architecture
Paperless-ngx consists of the following components:

View File

@@ -16,6 +16,7 @@ classifiers = [
# This will allow testing to not install a webserver, mysql, etc
dependencies = [
"azure-ai-documentintelligence>=1.0.2",
"babel>=2.17",
"bleach~=6.3.0",
"celery[redis]~=5.5.1",
@@ -252,6 +253,7 @@ testpaths = [
"src/paperless_tesseract/tests/",
"src/paperless_tika/tests",
"src/paperless_text/tests/",
"src/paperless_remote/tests/",
]
addopts = [
"--pythonwarnings=all",

View File

@@ -816,7 +816,7 @@
<source>Jump to bottom</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
<context context-type="linenumber">60</context>
<context context-type="linenumber">62</context>
</context-group>
</trans-unit>
<trans-unit id="1255048712725285892" datatype="html">

View File

@@ -53,12 +53,12 @@
"@angular/cli": "~20.3.10",
"@angular/compiler-cli": "~20.3.12",
"@codecov/webpack-plugin": "^1.9.1",
"@playwright/test": "^1.56.1",
"@playwright/test": "^1.57.0",
"@types/jest": "^30.0.0",
"@types/node": "^24.10.1",
"@typescript-eslint/eslint-plugin": "^8.47.0",
"@typescript-eslint/parser": "^8.47.0",
"@typescript-eslint/utils": "^8.47.0",
"@typescript-eslint/eslint-plugin": "^8.48.1",
"@typescript-eslint/parser": "^8.48.1",
"@typescript-eslint/utils": "^8.48.1",
"eslint": "^9.39.1",
"jest": "30.2.0",
"jest-environment-jsdom": "^30.2.0",
@@ -68,7 +68,7 @@
"prettier-plugin-organize-imports": "^4.3.0",
"ts-node": "~10.9.1",
"typescript": "^5.8.3",
"webpack": "^5.102.1"
"webpack": "^5.103.0"
},
"packageManager": "pnpm@10.17.1",
"pnpm": {

300
src-ui/pnpm-lock.yaml generated
View File

@@ -107,13 +107,13 @@ importers:
version: 20.6.0(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/eslint-plugin':
specifier: 20.6.0
version: 20.6.0(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
version: 20.6.0(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/eslint-plugin-template':
specifier: 20.6.0
version: 20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.47.0)(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
version: 20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.48.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/schematics':
specifier: 20.6.0
version: 20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.47.0)(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
version: 20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.48.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/template-parser':
specifier: 20.6.0
version: 20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
@@ -128,10 +128,10 @@ importers:
version: 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
'@codecov/webpack-plugin':
specifier: ^1.9.1
version: 1.9.1(webpack@5.102.1)
version: 1.9.1(webpack@5.103.0)
'@playwright/test':
specifier: ^1.56.1
version: 1.56.1
specifier: ^1.57.0
version: 1.57.0
'@types/jest':
specifier: ^30.0.0
version: 30.0.0
@@ -139,14 +139,14 @@ importers:
specifier: ^24.10.1
version: 24.10.1
'@typescript-eslint/eslint-plugin':
specifier: ^8.47.0
version: 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
specifier: ^8.48.1
version: 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/parser':
specifier: ^8.47.0
version: 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
specifier: ^8.48.1
version: 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/utils':
specifier: ^8.47.0
version: 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
specifier: ^8.48.1
version: 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
eslint:
specifier: ^9.39.1
version: 9.39.1(jiti@1.21.7)
@@ -175,8 +175,8 @@ importers:
specifier: ^5.8.3
version: 5.8.3
webpack:
specifier: ^5.102.1
version: 5.102.1
specifier: ^5.103.0
version: 5.103.0
packages:
@@ -2565,8 +2565,8 @@ packages:
resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
'@playwright/test@1.56.1':
resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==}
'@playwright/test@1.57.0':
resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==}
engines: {node: '>=18'}
hasBin: true
@@ -2970,63 +2970,63 @@ packages:
'@types/yargs@17.0.33':
resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
'@typescript-eslint/eslint-plugin@8.47.0':
resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==}
'@typescript-eslint/eslint-plugin@8.48.1':
resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.47.0
'@typescript-eslint/parser': ^8.48.1
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/parser@8.47.0':
resolution: {integrity: sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==}
'@typescript-eslint/parser@8.48.1':
resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.47.0':
resolution: {integrity: sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==}
'@typescript-eslint/project-service@8.48.1':
resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/scope-manager@8.47.0':
resolution: {integrity: sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==}
'@typescript-eslint/scope-manager@8.48.1':
resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.47.0':
resolution: {integrity: sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==}
'@typescript-eslint/tsconfig-utils@8.48.1':
resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/type-utils@8.47.0':
resolution: {integrity: sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==}
'@typescript-eslint/type-utils@8.48.1':
resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/types@8.47.0':
resolution: {integrity: sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==}
'@typescript-eslint/types@8.48.1':
resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.47.0':
resolution: {integrity: sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==}
'@typescript-eslint/typescript-estree@8.48.1':
resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/utils@8.47.0':
resolution: {integrity: sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==}
'@typescript-eslint/utils@8.48.1':
resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/visitor-keys@8.47.0':
resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==}
'@typescript-eslint/visitor-keys@8.48.1':
resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@ungap/structured-clone@1.3.0':
@@ -3408,6 +3408,10 @@ packages:
resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==}
hasBin: true
baseline-browser-mapping@2.9.4:
resolution: {integrity: sha512-ZCQ9GEWl73BVm8bu5Fts8nt7MHdbt5vY9bP6WGnUh+r3l8M7CgfyTlwsgCbMC66BNxPr6Xoce3j66Ms5YUQTNA==}
hasBin: true
batch@0.6.1:
resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==}
@@ -3466,6 +3470,11 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
bs-logger@0.2.6:
resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
engines: {node: '>= 6'}
@@ -3514,6 +3523,9 @@ packages:
caniuse-lite@1.0.30001755:
resolution: {integrity: sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==}
caniuse-lite@1.0.30001759:
resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==}
canvas@3.0.0:
resolution: {integrity: sha512-NtcIBY88FjymQy+g2g5qnuP5IslrbWCQ3A6rSr1PeuYxVRapRZ3BZCrDyAakvI6CuDYidgZaf55ygulFVwROdg==}
engines: {node: ^18.12.0 || >= 20.9.0}
@@ -3896,6 +3908,9 @@ packages:
electron-to-chromium@1.5.255:
resolution: {integrity: sha512-Z9oIp4HrFF/cZkDPMpz2XSuVpc1THDpT4dlmATFlJUIBVCy9Vap5/rIXsASP1CscBacBqhabwh8vLctqBwEerQ==}
electron-to-chromium@1.5.266:
resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==}
emittery@0.13.1:
resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
engines: {node: '>=12'}
@@ -5150,9 +5165,9 @@ packages:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
mime-types@3.0.1:
resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==}
engines: {node: '>= 0.6'}
mime-types@3.0.2:
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
engines: {node: '>=18'}
mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
@@ -5628,13 +5643,13 @@ packages:
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
engines: {node: '>=8'}
playwright-core@1.56.1:
resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==}
playwright-core@1.57.0:
resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==}
engines: {node: '>=18'}
hasBin: true
playwright@1.56.1:
resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==}
playwright@1.57.0:
resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==}
engines: {node: '>=18'}
hasBin: true
@@ -6268,8 +6283,8 @@ packages:
resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==}
engines: {node: '>=18'}
terser-webpack-plugin@5.3.14:
resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==}
terser-webpack-plugin@5.3.15:
resolution: {integrity: sha512-PGkOdpRFK+rb1TzVz+msVhw4YMRT9txLF4kRqvJhGhCM324xuR3REBSHALN+l+sAhKUmz0aotnjp5D+P83mLhQ==}
engines: {node: '>= 10.13.0'}
peerDependencies:
'@swc/core': '*'
@@ -6547,6 +6562,12 @@ packages:
peerDependencies:
browserslist: '>= 4.21.0'
update-browserslist-db@1.2.2:
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -6741,8 +6762,8 @@ packages:
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
webpack@5.102.1:
resolution: {integrity: sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==}
webpack@5.103.0:
resolution: {integrity: sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==}
engines: {node: '>=10.13.0'}
hasBin: true
peerDependencies:
@@ -7149,7 +7170,7 @@ snapshots:
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.2000.4(chokidar@4.0.3)
'@angular-devkit/build-webpack': 0.2000.4(chokidar@4.0.3)(webpack-dev-server@5.2.1(webpack@5.102.1))(webpack@5.99.8(esbuild@0.25.5))
'@angular-devkit/build-webpack': 0.2000.4(chokidar@4.0.3)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack@5.99.8(esbuild@0.25.5))
'@angular-devkit/core': 20.0.4(chokidar@4.0.3)
'@angular/build': 20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)
'@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
@@ -7168,7 +7189,7 @@ snapshots:
ansi-colors: 4.1.3
autoprefixer: 10.4.21(postcss@8.5.3)
babel-loader: 10.0.0(@babel/core@7.27.1)(webpack@5.99.8(esbuild@0.25.5))
browserslist: 4.28.0
browserslist: 4.28.1
copy-webpack-plugin: 13.0.0(webpack@5.99.8(esbuild@0.25.5))
css-loader: 7.1.2(webpack@5.99.8(esbuild@0.25.5))
esbuild-wasm: 0.25.5
@@ -7235,12 +7256,12 @@ snapshots:
- webpack-cli
- yaml
'@angular-devkit/build-webpack@0.2000.4(chokidar@4.0.3)(webpack-dev-server@5.2.1(webpack@5.102.1))(webpack@5.99.8(esbuild@0.25.5))':
'@angular-devkit/build-webpack@0.2000.4(chokidar@4.0.3)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack@5.99.8(esbuild@0.25.5))':
dependencies:
'@angular-devkit/architect': 0.2000.4(chokidar@4.0.3)
rxjs: 7.8.2
webpack: 5.99.8(esbuild@0.25.5)
webpack-dev-server: 5.2.1(webpack@5.102.1)
webpack-dev-server: 5.2.1(webpack@5.103.0)
transitivePeerDependencies:
- chokidar
@@ -7287,33 +7308,33 @@ snapshots:
'@angular-eslint/bundled-angular-compiler@20.6.0': {}
'@angular-eslint/eslint-plugin-template@20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.47.0)(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@angular-eslint/eslint-plugin-template@20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.48.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@angular-eslint/bundled-angular-compiler': 20.6.0
'@angular-eslint/template-parser': 20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/utils': 20.6.0(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/utils': 20.6.0(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
aria-query: 5.3.2
axobject-query: 4.1.0
eslint: 9.39.1(jiti@1.21.7)
typescript: 5.8.3
'@angular-eslint/eslint-plugin@20.6.0(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@angular-eslint/eslint-plugin@20.6.0(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@angular-eslint/bundled-angular-compiler': 20.6.0
'@angular-eslint/utils': 20.6.0(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/utils': 20.6.0(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
eslint: 9.39.1(jiti@1.21.7)
ts-api-utils: 2.1.0(typescript@5.8.3)
typescript: 5.8.3
'@angular-eslint/schematics@20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.47.0)(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@angular-eslint/schematics@20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.48.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@angular-devkit/core': 20.3.10(chokidar@4.0.3)
'@angular-devkit/schematics': 20.3.10(chokidar@4.0.3)
'@angular-eslint/eslint-plugin': 20.6.0(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/eslint-plugin-template': 20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.47.0)(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/eslint-plugin': 20.6.0(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/eslint-plugin-template': 20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.48.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
ignore: 7.0.5
semver: 7.7.3
strip-json-comments: 3.1.1
@@ -7332,10 +7353,10 @@ snapshots:
eslint-scope: 8.4.0
typescript: 5.8.3
'@angular-eslint/utils@20.6.0(@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@angular-eslint/utils@20.6.0(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@angular-eslint/bundled-angular-compiler': 20.6.0
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
eslint: 9.39.1(jiti@1.21.7)
typescript: 5.8.3
@@ -7351,7 +7372,7 @@ snapshots:
'@inquirer/confirm': 5.1.10(@types/node@24.10.1)
'@vitejs/plugin-basic-ssl': 2.0.0(vite@6.3.5(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(yaml@2.7.0))
beasties: 0.3.4
browserslist: 4.28.0
browserslist: 4.28.1
esbuild: 0.25.5
https-proxy-agent: 7.0.6
istanbul-lib-instrument: 6.0.3
@@ -7657,7 +7678,7 @@ snapshots:
dependencies:
'@babel/compat-data': 7.28.5
'@babel/helper-validator-option': 7.27.1
browserslist: 4.28.0
browserslist: 4.28.1
lru-cache: 5.1.1
semver: 6.3.1
@@ -8388,11 +8409,11 @@ snapshots:
unplugin: 1.16.1
zod: 3.25.76
'@codecov/webpack-plugin@1.9.1(webpack@5.102.1)':
'@codecov/webpack-plugin@1.9.1(webpack@5.103.0)':
dependencies:
'@codecov/bundler-plugin-core': 1.9.1
unplugin: 1.16.1
webpack: 5.102.1
webpack: 5.103.0
'@cspotcode/source-map-support@0.8.1':
dependencies:
@@ -9578,9 +9599,9 @@ snapshots:
'@pkgr/core@0.2.9': {}
'@playwright/test@1.56.1':
'@playwright/test@1.57.0':
dependencies:
playwright: 1.56.1
playwright: 1.57.0
'@popperjs/core@2.11.8': {}
@@ -9946,14 +9967,14 @@ snapshots:
dependencies:
'@types/yargs-parser': 21.0.3
'@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.47.0
'@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.47.0
'@typescript-eslint/parser': 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.48.1
'@typescript-eslint/type-utils': 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.48.1
eslint: 9.39.1(jiti@1.21.7)
graphemer: 1.4.0
ignore: 7.0.5
@@ -9963,41 +9984,41 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.47.0
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.47.0
'@typescript-eslint/scope-manager': 8.48.1
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/typescript-estree': 8.48.1(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.48.1
debug: 4.4.3
eslint: 9.39.1(jiti@1.21.7)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.47.0(typescript@5.8.3)':
'@typescript-eslint/project-service@8.48.1(typescript@5.8.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.8.3)
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.8.3)
'@typescript-eslint/types': 8.48.1
debug: 4.4.3
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.47.0':
'@typescript-eslint/scope-manager@8.48.1':
dependencies:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/visitor-keys': 8.47.0
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/visitor-keys': 8.48.1
'@typescript-eslint/tsconfig-utils@8.47.0(typescript@5.8.3)':
'@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.8.3)':
dependencies:
typescript: 5.8.3
'@typescript-eslint/type-utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@typescript-eslint/type-utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.8.3)
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/typescript-estree': 8.48.1(typescript@5.8.3)
'@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
debug: 4.4.3
eslint: 9.39.1(jiti@1.21.7)
ts-api-utils: 2.1.0(typescript@5.8.3)
@@ -10005,38 +10026,37 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.47.0': {}
'@typescript-eslint/types@8.48.1': {}
'@typescript-eslint/typescript-estree@8.47.0(typescript@5.8.3)':
'@typescript-eslint/typescript-estree@8.48.1(typescript@5.8.3)':
dependencies:
'@typescript-eslint/project-service': 8.47.0(typescript@5.8.3)
'@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.8.3)
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/visitor-keys': 8.47.0
'@typescript-eslint/project-service': 8.48.1(typescript@5.8.3)
'@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.8.3)
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/visitor-keys': 8.48.1
debug: 4.4.3
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.7.3
tinyglobby: 0.2.15
ts-api-utils: 2.1.0(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
'@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.7))
'@typescript-eslint/scope-manager': 8.47.0
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.48.1
'@typescript-eslint/types': 8.48.1
'@typescript-eslint/typescript-estree': 8.48.1(typescript@5.8.3)
eslint: 9.39.1(jiti@1.21.7)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.47.0':
'@typescript-eslint/visitor-keys@8.48.1':
dependencies:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/types': 8.48.1
eslint-visitor-keys: 4.2.1
'@ungap/structured-clone@1.3.0': {}
@@ -10205,7 +10225,7 @@ snapshots:
accepts@2.0.0:
dependencies:
mime-types: 3.0.1
mime-types: 3.0.2
negotiator: 1.0.0
acorn-globals@7.0.1:
@@ -10329,8 +10349,8 @@ snapshots:
autoprefixer@10.4.21(postcss@8.5.3):
dependencies:
browserslist: 4.28.0
caniuse-lite: 1.0.30001755
browserslist: 4.28.1
caniuse-lite: 1.0.30001759
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
@@ -10428,6 +10448,8 @@ snapshots:
baseline-browser-mapping@2.8.29: {}
baseline-browser-mapping@2.9.4: {}
batch@0.6.1: {}
beasties@0.3.4:
@@ -10528,6 +10550,14 @@ snapshots:
node-releases: 2.0.27
update-browserslist-db: 1.1.4(browserslist@4.28.0)
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.9.4
caniuse-lite: 1.0.30001759
electron-to-chromium: 1.5.266
node-releases: 2.0.27
update-browserslist-db: 1.2.2(browserslist@4.28.1)
bs-logger@0.2.6:
dependencies:
fast-json-stable-stringify: 2.1.0
@@ -10583,6 +10613,8 @@ snapshots:
caniuse-lite@1.0.30001755: {}
caniuse-lite@1.0.30001759: {}
canvas@3.0.0:
dependencies:
node-addon-api: 7.1.1
@@ -10740,7 +10772,7 @@ snapshots:
core-js-compat@3.43.0:
dependencies:
browserslist: 4.28.0
browserslist: 4.28.1
core-util-is@1.0.3: {}
@@ -10925,6 +10957,8 @@ snapshots:
electron-to-chromium@1.5.255: {}
electron-to-chromium@1.5.266: {}
emittery@0.13.1: {}
emoji-regex@10.6.0: {}
@@ -11276,7 +11310,7 @@ snapshots:
fresh: 2.0.0
http-errors: 2.0.0
merge-descriptors: 2.0.0
mime-types: 3.0.1
mime-types: 3.0.2
on-finished: 2.4.1
once: 1.4.0
parseurl: 1.3.3
@@ -12623,7 +12657,7 @@ snapshots:
dependencies:
mime-db: 1.52.0
mime-types@3.0.1:
mime-types@3.0.2:
dependencies:
mime-db: 1.54.0
@@ -13118,11 +13152,11 @@ snapshots:
dependencies:
find-up: 4.1.0
playwright-core@1.56.1: {}
playwright-core@1.57.0: {}
playwright@1.56.1:
playwright@1.57.0:
dependencies:
playwright-core: 1.56.1
playwright-core: 1.57.0
optionalDependencies:
fsevents: 2.3.2
@@ -13550,7 +13584,7 @@ snapshots:
etag: 1.8.1
fresh: 2.0.0
http-errors: 2.0.0
mime-types: 3.0.1
mime-types: 3.0.2
ms: 2.1.3
on-finished: 2.4.1
range-parser: 1.2.1
@@ -13880,7 +13914,7 @@ snapshots:
minizlib: 3.1.0
yallist: 5.0.0
terser-webpack-plugin@5.3.14(esbuild@0.25.5)(webpack@5.99.8(esbuild@0.25.5)):
terser-webpack-plugin@5.3.15(esbuild@0.25.5)(webpack@5.99.8(esbuild@0.25.5)):
dependencies:
'@jridgewell/trace-mapping': 0.3.31
jest-worker: 27.5.1
@@ -13891,14 +13925,14 @@ snapshots:
optionalDependencies:
esbuild: 0.25.5
terser-webpack-plugin@5.3.14(webpack@5.102.1):
terser-webpack-plugin@5.3.15(webpack@5.103.0):
dependencies:
'@jridgewell/trace-mapping': 0.3.31
jest-worker: 27.5.1
schema-utils: 4.3.3
serialize-javascript: 6.0.2
terser: 5.44.1
webpack: 5.102.1
webpack: 5.103.0
terser@5.39.1:
dependencies:
@@ -14086,7 +14120,7 @@ snapshots:
dependencies:
content-type: 1.0.5
media-typer: 1.1.0
mime-types: 3.0.1
mime-types: 3.0.2
typed-assert@1.0.9: {}
@@ -14161,6 +14195,12 @@ snapshots:
escalade: 3.2.0
picocolors: 1.1.1
update-browserslist-db@1.2.2(browserslist@4.28.1):
dependencies:
browserslist: 4.28.1
escalade: 3.2.0
picocolors: 1.1.1
uri-js@4.4.1:
dependencies:
punycode: 2.3.1
@@ -14264,7 +14304,7 @@ snapshots:
webidl-conversions@7.0.0: {}
webpack-dev-middleware@7.4.2(webpack@5.102.1):
webpack-dev-middleware@7.4.2(webpack@5.103.0):
dependencies:
colorette: 2.0.20
memfs: 4.17.2
@@ -14273,7 +14313,7 @@ snapshots:
range-parser: 1.2.1
schema-utils: 4.3.3
optionalDependencies:
webpack: 5.102.1
webpack: 5.103.0
webpack-dev-middleware@7.4.2(webpack@5.99.8(esbuild@0.25.5)):
dependencies:
@@ -14286,7 +14326,7 @@ snapshots:
optionalDependencies:
webpack: 5.99.8(esbuild@0.25.5)
webpack-dev-server@5.2.1(webpack@5.102.1):
webpack-dev-server@5.2.1(webpack@5.103.0):
dependencies:
'@types/bonjour': 3.5.13
'@types/connect-history-api-fallback': 1.5.4
@@ -14314,10 +14354,10 @@ snapshots:
serve-index: 1.9.1
sockjs: 0.3.24
spdy: 4.0.2
webpack-dev-middleware: 7.4.2(webpack@5.102.1)
webpack-dev-middleware: 7.4.2(webpack@5.103.0)
ws: 8.18.3
optionalDependencies:
webpack: 5.102.1
webpack: 5.103.0
transitivePeerDependencies:
- bufferutil
- debug
@@ -14377,7 +14417,7 @@ snapshots:
webpack-virtual-modules@0.6.2: {}
webpack@5.102.1:
webpack@5.103.0:
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.8
@@ -14387,7 +14427,7 @@ snapshots:
'@webassemblyjs/wasm-parser': 1.14.1
acorn: 8.15.0
acorn-import-phases: 1.0.4(acorn@8.15.0)
browserslist: 4.28.0
browserslist: 4.28.1
chrome-trace-event: 1.0.4
enhanced-resolve: 5.18.3
es-module-lexer: 1.7.0
@@ -14401,7 +14441,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 4.3.3
tapable: 2.3.0
terser-webpack-plugin: 5.3.14(webpack@5.102.1)
terser-webpack-plugin: 5.3.15(webpack@5.103.0)
watchpack: 2.4.4
webpack-sources: 3.3.3
transitivePeerDependencies:
@@ -14418,7 +14458,7 @@ snapshots:
'@webassemblyjs/wasm-edit': 1.14.1
'@webassemblyjs/wasm-parser': 1.14.1
acorn: 8.15.0
browserslist: 4.28.0
browserslist: 4.28.1
chrome-trace-event: 1.0.4
enhanced-resolve: 5.18.3
es-module-lexer: 1.7.0
@@ -14432,7 +14472,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 4.3.3
tapable: 2.3.0
terser-webpack-plugin: 5.3.14(esbuild@0.25.5)(webpack@5.99.8(esbuild@0.25.5))
terser-webpack-plugin: 5.3.15(esbuild@0.25.5)(webpack@5.99.8(esbuild@0.25.5))
watchpack: 2.4.4
webpack-sources: 3.3.3
transitivePeerDependencies:

View File

@@ -48,7 +48,9 @@
<ng-container i18n>Loading...</ng-container>
</div>
} @else {
<p *ngFor="let log of logs" class="m-0 p-0" [ngClass]="'log-entry-' + log.level">{{log.message}}</p>
@for (log of logs; track log) {
<p class="m-0 p-0" [ngClass]="'log-entry-' + log.level">{{log.message}}</p>
}
}
</div>
<button

View File

@@ -892,7 +892,7 @@
<context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
<context context-type="linenumber">60</context>
</context-group>
<target state="translated">Přejít na konec</target>
<target state="needs-translation">Jump to bottom</target>
</trans-unit>
<trans-unit id="1255048712725285892" datatype="html">
<source>Options to customize appearance, notifications and more. Settings apply to the &lt;strong&gt;current user only&lt;/strong&gt;.</source>
@@ -3952,7 +3952,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">121</context>
</context-group>
<target state="translated">Předchozí týden</target>
<target state="needs-translation">Previous week</target>
</trans-unit>
<trans-unit id="8586908745456864217" datatype="html">
<source>Previous month</source>
@@ -3960,7 +3960,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">135</context>
</context-group>
<target state="translated">Předchozí měsíc</target>
<target state="needs-translation">Previous month</target>
</trans-unit>
<trans-unit id="357608474534295480" datatype="html">
<source>Previous quarter</source>
@@ -3968,7 +3968,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">141</context>
</context-group>
<target state="translated">Předchozí čtvrtletí</target>
<target state="needs-translation">Previous quarter</target>
</trans-unit>
<trans-unit id="100513227838842152" datatype="html">
<source>Previous year</source>
@@ -3976,7 +3976,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">155</context>
</context-group>
<target state="translated">Předchozí rok</target>
<target state="needs-translation">Previous year</target>
</trans-unit>
<trans-unit id="8743659855412792665" datatype="html" approved="yes">
<source>Matching algorithm</source>

View File

@@ -886,13 +886,13 @@
</context-group>
<target state="final">Wird geladen...</target>
</trans-unit>
<trans-unit id="7831218302373733360" datatype="html" approved="yes">
<trans-unit id="7831218302373733360" datatype="html">
<source>Jump to bottom</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
<context context-type="linenumber">60</context>
</context-group>
<target state="final">Nach unten</target>
<target state="translated">Nach unten</target>
</trans-unit>
<trans-unit id="1255048712725285892" datatype="html" approved="yes">
<source>Options to customize appearance, notifications and more. Settings apply to the &lt;strong&gt;current user only&lt;/strong&gt;.</source>
@@ -2150,21 +2150,21 @@
</context-group>
<target state="final">Alle <x id="PH" equiv-text="tasks.size"/> Aufgaben verwerfen?</target>
</trans-unit>
<trans-unit id="3597309129998924778" datatype="html" approved="yes">
<trans-unit id="3597309129998924778" datatype="html">
<source>Error dismissing tasks</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">161</context>
</context-group>
<target state="final">Fehler beim Verwerfen der Aufgaben</target>
<target state="translated">Fehler beim Verwerfen der Aufgaben</target>
</trans-unit>
<trans-unit id="2132179171926568807" datatype="html" approved="yes">
<trans-unit id="2132179171926568807" datatype="html">
<source>Error dismissing task</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">170</context>
</context-group>
<target state="final">Fehler beim Verwerfen der Aufgabe</target>
<target state="translated">Fehler beim Verwerfen der Aufgabe</target>
</trans-unit>
<trans-unit id="9011556615675272238" datatype="html" approved="yes">
<source>queued</source>
@@ -5674,29 +5674,29 @@
</context-group>
<target state="final">Webhook</target>
</trans-unit>
<trans-unit id="4522609911791833187" datatype="html" approved="yes">
<trans-unit id="4522609911791833187" datatype="html">
<source>Has any of these tags</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">203</context>
</context-group>
<target state="final">Hat beliebige dieser Tags</target>
<target state="translated">Hat beliebige dieser Tags</target>
</trans-unit>
<trans-unit id="4166903555074156852" datatype="html" approved="yes">
<trans-unit id="4166903555074156852" datatype="html">
<source>Has all of these tags</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">210</context>
</context-group>
<target state="final">Hat alle diese Tags</target>
<target state="translated">Hat alle diese Tags</target>
</trans-unit>
<trans-unit id="6624363795312783141" datatype="html" approved="yes">
<trans-unit id="6624363795312783141" datatype="html">
<source>Does not have these tags</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts</context>
<context context-type="linenumber">217</context>
</context-group>
<target state="final">Hat diese Tags nicht</target>
<target state="translated">Hat diese Tags nicht</target>
</trans-unit>
<trans-unit id="5281365940563983618" datatype="html" approved="yes">
<source>Has correspondent</source>

View File

@@ -892,7 +892,7 @@
<context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
<context context-type="linenumber">60</context>
</context-group>
<target state="translated">Ugrás az oldal aljára</target>
<target state="needs-translation">Jump to bottom</target>
</trans-unit>
<trans-unit id="1255048712725285892" datatype="html">
<source>Options to customize appearance, notifications and more. Settings apply to the &lt;strong&gt;current user only&lt;/strong&gt;.</source>
@@ -3952,7 +3952,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">121</context>
</context-group>
<target state="translated">Előző hét</target>
<target state="needs-translation">Previous week</target>
</trans-unit>
<trans-unit id="8586908745456864217" datatype="html">
<source>Previous month</source>
@@ -3960,7 +3960,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">135</context>
</context-group>
<target state="translated">Előző hónap</target>
<target state="needs-translation">Previous month</target>
</trans-unit>
<trans-unit id="357608474534295480" datatype="html">
<source>Previous quarter</source>
@@ -3968,7 +3968,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">141</context>
</context-group>
<target state="translated">Előző negyedév</target>
<target state="needs-translation">Previous quarter</target>
</trans-unit>
<trans-unit id="100513227838842152" datatype="html">
<source>Previous year</source>
@@ -3976,7 +3976,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">155</context>
</context-group>
<target state="translated">Előző év</target>
<target state="needs-translation">Previous year</target>
</trans-unit>
<trans-unit id="8743659855412792665" datatype="html">
<source>Matching algorithm</source>
@@ -5276,7 +5276,7 @@
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
<context context-type="linenumber">183</context>
</context-group>
<target state="translated">Haladó szűrők</target>
<target state="needs-translation">Advanced Filters</target>
</trans-unit>
<trans-unit id="910026778839409110" datatype="html">
<source>Add filter</source>
@@ -5284,7 +5284,7 @@
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
<context context-type="linenumber">190</context>
</context-group>
<target state="translated">Szűrő hozzáadása</target>
<target state="needs-translation">Add filter</target>
</trans-unit>
<trans-unit id="5671193617280178107" datatype="html">
<source>No advanced workflow filters defined.</source>

View File

@@ -9831,7 +9831,7 @@
<context context-type="sourcefile">src/app/components/manage/mail/processed-mail-dialog/processed-mail-dialog.component.html</context>
<context context-type="linenumber">2</context>
</context-group>
<target state="translated">Posta processata per</target>
<target state="needs-translation">Processed Mail for <x id="START_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;em&gt;"/><x id="INTERPOLATION" equiv-text="{{ rule.name }}"/><x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/></target>
</trans-unit>
<trans-unit id="1991019495862291373" datatype="html">
<source>No processed email messages found.</source>

View File

@@ -892,7 +892,7 @@
<context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
<context context-type="linenumber">60</context>
</context-group>
<target state="translated">Skoči na dno</target>
<target state="needs-translation">Jump to bottom</target>
</trans-unit>
<trans-unit id="1255048712725285892" datatype="html">
<source>Options to customize appearance, notifications and more. Settings apply to the &lt;strong&gt;current user only&lt;/strong&gt;.</source>
@@ -3952,7 +3952,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">121</context>
</context-group>
<target state="translated">Prethodna nedelja</target>
<target state="needs-translation">Previous week</target>
</trans-unit>
<trans-unit id="8586908745456864217" datatype="html">
<source>Previous month</source>
@@ -3960,7 +3960,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">135</context>
</context-group>
<target state="translated">Prethodni mesec</target>
<target state="needs-translation">Previous month</target>
</trans-unit>
<trans-unit id="357608474534295480" datatype="html">
<source>Previous quarter</source>
@@ -3968,7 +3968,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">141</context>
</context-group>
<target state="translated">Prethodni kvartal</target>
<target state="needs-translation">Previous quarter</target>
</trans-unit>
<trans-unit id="100513227838842152" datatype="html">
<source>Previous year</source>
@@ -3976,7 +3976,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">155</context>
</context-group>
<target state="translated">Prethodna godina</target>
<target state="needs-translation">Previous year</target>
</trans-unit>
<trans-unit id="8743659855412792665" datatype="html">
<source>Matching algorithm</source>

View File

@@ -7172,7 +7172,7 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">323</context>
</context-group>
<target state="translated">Muhataba göre filtrele</target>
<target state="translated">Muhataba göre süz</target>
</trans-unit>
<trans-unit id="78870852467682010" datatype="html">
<source>Filter by document type</source>
@@ -8130,7 +8130,7 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
<context context-type="linenumber">51</context>
</context-group>
<target state="translated">Muhatabları filtrele</target>
<target state="translated">Muhataba göre süz</target>
</trans-unit>
<trans-unit id="2947613869920454977" datatype="html">
<source>Filter document types</source>
@@ -8142,7 +8142,7 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
<context context-type="linenumber">62</context>
</context-group>
<target state="translated">Belge türlerine göre filtrele</target>
<target state="translated">Belge türlerini göre filtrele</target>
</trans-unit>
<trans-unit id="8816999377397522522" datatype="html">
<source>Filter storage paths</source>
@@ -8669,7 +8669,7 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
<context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
<context context-type="linenumber">43</context>
</context-group>
<target state="translated">Muhatap filtresini aç/kapat</target>
<target state="translated">Muhatap süzgecini aç/kapat</target>
</trans-unit>
<trans-unit id="5319701482646590642" datatype="html">
<source>Toggle document type filter</source>
@@ -8817,7 +8817,7 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">143</context>
</context-group>
<target state="translated">(filtrelendi)</target>
<target state="translated">(süzüldü)</target>
</trans-unit>
<trans-unit id="6849725902312323996" datatype="html">
<source>Reset filters</source>
@@ -8829,7 +8829,7 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
<context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.html</context>
<context context-type="linenumber">107</context>
</context-group>
<target state="translated">Filtreleri sıfırla</target>
<target state="translated">Süzgeçleri sıfırla</target>
</trans-unit>
<trans-unit id="1559883523769732271" datatype="html">
<source>Error while loading documents</source>
@@ -9885,7 +9885,7 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="&lt;/em&gt;"/> krite
<context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
<context context-type="linenumber">20</context>
</context-group>
<target state="translated">Şuna göre filtrele:</target>
<target state="translated">Şuna göre süz:</target>
</trans-unit>
<trans-unit id="1383365546483928780" datatype="html">
<source>Matching</source>

View File

@@ -764,7 +764,7 @@
<context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
<context context-type="linenumber">17</context>
</context-group>
<target state="translated">行</target>
<target state="needs-translation">lines</target>
</trans-unit>
<trans-unit id="8838884664569764142" datatype="html">
<source>Auto refresh</source>
@@ -892,7 +892,7 @@
<context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
<context context-type="linenumber">60</context>
</context-group>
<target state="translated">跳转到底部</target>
<target state="needs-translation">Jump to bottom</target>
</trans-unit>
<trans-unit id="1255048712725285892" datatype="html">
<source>Options to customize appearance, notifications and more. Settings apply to the &lt;strong&gt;current user only&lt;/strong&gt;.</source>
@@ -3952,7 +3952,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">121</context>
</context-group>
<target state="translated">上周</target>
<target state="needs-translation">Previous week</target>
</trans-unit>
<trans-unit id="8586908745456864217" datatype="html">
<source>Previous month</source>
@@ -3960,7 +3960,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">135</context>
</context-group>
<target state="translated">上个月</target>
<target state="needs-translation">Previous month</target>
</trans-unit>
<trans-unit id="357608474534295480" datatype="html">
<source>Previous quarter</source>
@@ -3968,7 +3968,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">141</context>
</context-group>
<target state="translated">上个季度</target>
<target state="needs-translation">Previous quarter</target>
</trans-unit>
<trans-unit id="100513227838842152" datatype="html">
<source>Previous year</source>
@@ -3976,7 +3976,7 @@
<context context-type="sourcefile">src/app/components/common/dates-dropdown/dates-dropdown.component.ts</context>
<context context-type="linenumber">155</context>
</context-group>
<target state="translated">上年</target>
<target state="needs-translation">Previous year</target>
</trans-unit>
<trans-unit id="8743659855412792665" datatype="html">
<source>Matching algorithm</source>
@@ -8735,7 +8735,7 @@
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
<context context-type="linenumber">18</context>
</context-group>
<target state="translated">选择:</target>
<target state="needs-translation">Select:</target>
</trans-unit>
<trans-unit id="6252070156626006029" datatype="html">
<source>None</source>

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-03 00:36\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Czech\n"
"Language: cs_CZ\n"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-02 12:16\n"
"PO-Revision-Date: 2025-11-22 12:12\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -862,7 +862,7 @@ msgstr "hat alle diese Tags"
#: documents/models.py:1079
msgid "does not have these tag(s)"
msgstr "hat diese Tags nicht"
msgstr "hat diese Tags nicht)"
#: documents/models.py:1087
msgid "has this document type"
@@ -890,7 +890,7 @@ msgstr "hat diese Speicherpfade nicht"
#: documents/models.py:1128
msgid "filter custom field query"
msgstr "Benutzerdefinierte Feldabfrage filtern"
msgstr "Filtere nach benutzerdefiniertem Feld"
#: documents/models.py:1131
msgid "JSON-encoded custom field query expression."

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-04 00:37\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Persian\n"
"Language: fa_IR\n"
@@ -31,7 +31,7 @@ msgstr "Invalid custom field query expression"
#: documents/filters.py:424
msgid "Invalid expression list. Must be nonempty."
msgstr "لیست عبارت‌ها نامعتبر است. نباید خالی باشد."
msgstr ""
#: documents/filters.py:445
msgid "Invalid logical operator {op!r}"
@@ -51,7 +51,7 @@ msgstr ""
#: documents/filters.py:669 documents/models.py:135
msgid "Maximum nesting depth exceeded."
msgstr "حداکثر عمق تودرتویی بیش از حد مجاز است."
msgstr ""
#: documents/filters.py:854
msgid "Custom field not found"
@@ -79,7 +79,7 @@ msgstr "مطابقت دقیق"
#: documents/models.py:59 documents/models.py:987
msgid "Regular expression"
msgstr "عبارت باقاعده"
msgstr ""
#: documents/models.py:60 documents/models.py:988
msgid "Fuzzy word"
@@ -136,11 +136,11 @@ msgstr "برچسب ها"
#: documents/models.py:123
msgid "Cannot set itself as parent."
msgstr "نمی‌تواند خودش را به عنوان والد تنظیم کند."
msgstr ""
#: documents/models.py:125
msgid "Cannot set parent to a descendant."
msgstr "نمی‌توان والد را به یک فرزند یا عضو پایین‌تر در سلسله‌مراتب تنظیم کرد."
msgstr ""
#: documents/models.py:142 documents/models.py:190
msgid "document type"
@@ -758,7 +758,7 @@ msgstr "انتخاب کردن"
#: documents/models.py:795
msgid "Long Text"
msgstr "متن طولانی"
msgstr ""
#: documents/models.py:807
msgid "data type"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-02 12:16\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Hungarian\n"
"Language: hu_HU\n"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-03 12:15\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Indonesian\n"
"Language: id_ID\n"
@@ -136,11 +136,11 @@ msgstr "label"
#: documents/models.py:123
msgid "Cannot set itself as parent."
msgstr "Tidak dapat menetapkan dirinya sebagai induk."
msgstr ""
#: documents/models.py:125
msgid "Cannot set parent to a descendant."
msgstr "Tidak dapat menetapkan induk ke keturunan."
msgstr ""
#: documents/models.py:142 documents/models.py:190
msgid "document type"
@@ -858,11 +858,11 @@ msgstr "memiliki label(-label) ini"
#: documents/models.py:1072
msgid "has all of these tag(s)"
msgstr "memiliki semua label ini"
msgstr ""
#: documents/models.py:1079
msgid "does not have these tag(s)"
msgstr "tidak memiliki semua label ini"
msgstr ""
#: documents/models.py:1087
msgid "has this document type"
@@ -870,7 +870,7 @@ msgstr "memiliki jenis dokumen ini"
#: documents/models.py:1094
msgid "does not have these document type(s)"
msgstr "tidak memiliki semua tipe dokumen ini"
msgstr ""
#: documents/models.py:1102
msgid "has this correspondent"
@@ -878,15 +878,15 @@ msgstr "memiliki koresponden ini"
#: documents/models.py:1109
msgid "does not have these correspondent(s)"
msgstr "tidak memiliki koresponden ini"
msgstr ""
#: documents/models.py:1117
msgid "has this storage path"
msgstr "memiliki jalur penyimpanan ini"
msgstr ""
#: documents/models.py:1124
msgid "does not have these storage path(s)"
msgstr "tidak memiliki jalur penyimpanan ini"
msgstr ""
#: documents/models.py:1128
msgid "filter custom field query"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-05 00:37\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Language: it_IT\n"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-04 00:37\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Romanian\n"
"Language: ro_RO\n"
@@ -136,7 +136,7 @@ msgstr "etichete"
#: documents/models.py:123
msgid "Cannot set itself as parent."
msgstr "Nu se poate seta ca părinte."
msgstr ""
#: documents/models.py:125
msgid "Cannot set parent to a descendant."
@@ -450,7 +450,7 @@ msgstr "query fulltext"
#: documents/models.py:526
msgid "more like this"
msgstr "mai multe ca aceasta"
msgstr ""
#: documents/models.py:527
msgid "has tags in"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-03 00:36\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Serbian (Latin)\n"
"Language: sr_CS\n"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-02 12:16\n"
"PO-Revision-Date: 2025-11-25 12:16\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Language: tr_TR\n"

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-14 16:09+0000\n"
"PO-Revision-Date: 2025-12-05 12:15\n"
"PO-Revision-Date: 2025-11-14 16:11\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"

View File

@@ -322,6 +322,7 @@ INSTALLED_APPS = [
"paperless_tesseract.apps.PaperlessTesseractConfig",
"paperless_text.apps.PaperlessTextConfig",
"paperless_mail.apps.PaperlessMailConfig",
"paperless_remote.apps.PaperlessRemoteParserConfig",
"django.contrib.admin",
"rest_framework",
"rest_framework.authtoken",
@@ -1401,3 +1402,10 @@ WEBHOOKS_ALLOW_INTERNAL_REQUESTS = __get_boolean(
"PAPERLESS_WEBHOOKS_ALLOW_INTERNAL_REQUESTS",
"true",
)
###############################################################################
# Remote Parser #
###############################################################################
REMOTE_OCR_ENGINE = os.getenv("PAPERLESS_REMOTE_OCR_ENGINE")
REMOTE_OCR_API_KEY = os.getenv("PAPERLESS_REMOTE_OCR_API_KEY")
REMOTE_OCR_ENDPOINT = os.getenv("PAPERLESS_REMOTE_OCR_ENDPOINT")

View File

@@ -0,0 +1,4 @@
# this is here so that django finds the checks.
from paperless_remote.checks import check_remote_parser_configured
__all__ = ["check_remote_parser_configured"]

View File

@@ -0,0 +1,14 @@
from django.apps import AppConfig
from paperless_remote.signals import remote_consumer_declaration
class PaperlessRemoteParserConfig(AppConfig):
name = "paperless_remote"
def ready(self):
from documents.signals import document_consumer_declaration
document_consumer_declaration.connect(remote_consumer_declaration)
AppConfig.ready(self)

View File

@@ -0,0 +1,17 @@
from django.conf import settings
from django.core.checks import Error
from django.core.checks import register
@register()
def check_remote_parser_configured(app_configs, **kwargs):
if settings.REMOTE_OCR_ENGINE == "azureai" and not (
settings.REMOTE_OCR_ENDPOINT and settings.REMOTE_OCR_API_KEY
):
return [
Error(
"Azure AI remote parser requires endpoint and API key to be configured.",
),
]
return []

View File

@@ -0,0 +1,118 @@
from pathlib import Path
from django.conf import settings
from paperless_tesseract.parsers import RasterisedDocumentParser
class RemoteEngineConfig:
def __init__(
self,
engine: str,
api_key: str | None = None,
endpoint: str | None = None,
):
self.engine = engine
self.api_key = api_key
self.endpoint = endpoint
def engine_is_valid(self):
valid = self.engine in ["azureai"] and self.api_key is not None
if self.engine == "azureai":
valid = valid and self.endpoint is not None
return valid
class RemoteDocumentParser(RasterisedDocumentParser):
"""
This parser uses a remote OCR engine to parse documents. Currently, it supports Azure AI Vision
as this is the only service that provides a remote OCR API with text-embedded PDF output.
"""
logging_name = "paperless.parsing.remote"
def get_settings(self) -> RemoteEngineConfig:
"""
Returns the configuration for the remote OCR engine, loaded from Django settings.
"""
return RemoteEngineConfig(
engine=settings.REMOTE_OCR_ENGINE,
api_key=settings.REMOTE_OCR_API_KEY,
endpoint=settings.REMOTE_OCR_ENDPOINT,
)
def supported_mime_types(self):
if self.settings.engine_is_valid():
return {
"application/pdf": ".pdf",
"image/png": ".png",
"image/jpeg": ".jpg",
"image/tiff": ".tiff",
"image/bmp": ".bmp",
"image/gif": ".gif",
"image/webp": ".webp",
}
else:
return {}
def azure_ai_vision_parse(
self,
file: Path,
) -> str | None:
"""
Uses Azure AI Vision to parse the document and return the text content.
It requests a searchable PDF output with embedded text.
The PDF is saved to the archive_path attribute.
Returns the text content extracted from the document.
If the parsing fails, it returns None.
"""
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import AnalyzeDocumentRequest
from azure.ai.documentintelligence.models import AnalyzeOutputOption
from azure.ai.documentintelligence.models import DocumentContentFormat
from azure.core.credentials import AzureKeyCredential
client = DocumentIntelligenceClient(
endpoint=self.settings.endpoint,
credential=AzureKeyCredential(self.settings.api_key),
)
try:
with file.open("rb") as f:
analyze_request = AnalyzeDocumentRequest(bytes_source=f.read())
poller = client.begin_analyze_document(
model_id="prebuilt-read",
body=analyze_request,
output_content_format=DocumentContentFormat.TEXT,
output=[AnalyzeOutputOption.PDF], # request searchable PDF output
content_type="application/json",
)
poller.wait()
result_id = poller.details["operation_id"]
result = poller.result()
# Download the PDF with embedded text
self.archive_path = self.tempdir / "archive.pdf"
with self.archive_path.open("wb") as f:
for chunk in client.get_analyze_result_pdf(
model_id="prebuilt-read",
result_id=result_id,
):
f.write(chunk)
return result.content
except Exception as e:
self.log.error(f"Azure AI Vision parsing failed: {e}")
finally:
client.close()
return None
def parse(self, document_path: Path, mime_type, file_name=None):
if not self.settings.engine_is_valid():
self.log.warning(
"No valid remote parser engine is configured, content will be empty.",
)
self.text = ""
elif self.settings.engine == "azureai":
self.text = self.azure_ai_vision_parse(document_path)

View File

@@ -0,0 +1,18 @@
def get_parser(*args, **kwargs):
from paperless_remote.parsers import RemoteDocumentParser
return RemoteDocumentParser(*args, **kwargs)
def get_supported_mime_types():
from paperless_remote.parsers import RemoteDocumentParser
return RemoteDocumentParser(None).supported_mime_types()
def remote_consumer_declaration(sender, **kwargs):
return {
"parser": get_parser,
"weight": 5,
"mime_types": get_supported_mime_types(),
}

View File

Binary file not shown.

View File

@@ -0,0 +1,24 @@
from unittest import TestCase
from django.test import override_settings
from paperless_remote import check_remote_parser_configured
class TestChecks(TestCase):
@override_settings(REMOTE_OCR_ENGINE=None)
def test_no_engine(self):
msgs = check_remote_parser_configured(None)
self.assertEqual(len(msgs), 0)
@override_settings(REMOTE_OCR_ENGINE="azureai")
@override_settings(REMOTE_OCR_API_KEY="somekey")
@override_settings(REMOTE_OCR_ENDPOINT=None)
def test_azure_no_endpoint(self):
msgs = check_remote_parser_configured(None)
self.assertEqual(len(msgs), 1)
self.assertTrue(
msgs[0].msg.startswith(
"Azure AI remote parser requires endpoint and API key to be configured.",
),
)

View File

@@ -0,0 +1,128 @@
import uuid
from pathlib import Path
from unittest import mock
from django.test import TestCase
from django.test import override_settings
from documents.tests.utils import DirectoriesMixin
from documents.tests.utils import FileSystemAssertsMixin
from paperless_remote.parsers import RemoteDocumentParser
from paperless_remote.signals import get_parser
class TestParser(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
SAMPLE_FILES = Path(__file__).resolve().parent / "samples"
def assertContainsStrings(self, content: str, strings: list[str]):
# Asserts that all strings appear in content, in the given order.
indices = []
for s in strings:
if s in content:
indices.append(content.index(s))
else:
self.fail(f"'{s}' is not in '{content}'")
self.assertListEqual(indices, sorted(indices))
@mock.patch("paperless_tesseract.parsers.run_subprocess")
@mock.patch("azure.ai.documentintelligence.DocumentIntelligenceClient")
def test_get_text_with_azure(self, mock_client_cls, mock_subprocess):
# Arrange mock Azure client
mock_client = mock.Mock()
mock_client_cls.return_value = mock_client
# Simulate poller result and its `.details`
mock_poller = mock.Mock()
mock_poller.wait.return_value = None
mock_poller.details = {"operation_id": "fake-op-id"}
mock_client.begin_analyze_document.return_value = mock_poller
mock_poller.result.return_value.content = "This is a test document."
# Return dummy PDF bytes
mock_client.get_analyze_result_pdf.return_value = [
b"%PDF-",
b"1.7 ",
b"FAKEPDF",
]
# Simulate pdftotext by writing dummy text to sidecar file
def fake_run(cmd, *args, **kwargs):
with Path(cmd[-1]).open("w", encoding="utf-8") as f:
f.write("This is a test document.")
mock_subprocess.side_effect = fake_run
with override_settings(
REMOTE_OCR_ENGINE="azureai",
REMOTE_OCR_API_KEY="somekey",
REMOTE_OCR_ENDPOINT="https://endpoint.cognitiveservices.azure.com",
):
parser = get_parser(uuid.uuid4())
parser.parse(
self.SAMPLE_FILES / "simple-digital.pdf",
"application/pdf",
)
self.assertContainsStrings(
parser.text.strip(),
["This is a test document."],
)
@mock.patch("azure.ai.documentintelligence.DocumentIntelligenceClient")
def test_get_text_with_azure_error_logged_and_returns_none(self, mock_client_cls):
mock_client = mock.Mock()
mock_client.begin_analyze_document.side_effect = RuntimeError("fail")
mock_client_cls.return_value = mock_client
with override_settings(
REMOTE_OCR_ENGINE="azureai",
REMOTE_OCR_API_KEY="somekey",
REMOTE_OCR_ENDPOINT="https://endpoint.cognitiveservices.azure.com",
):
parser = get_parser(uuid.uuid4())
with mock.patch.object(parser.log, "error") as mock_log_error:
parser.parse(
self.SAMPLE_FILES / "simple-digital.pdf",
"application/pdf",
)
self.assertIsNone(parser.text)
mock_client.begin_analyze_document.assert_called_once()
mock_client.close.assert_called_once()
mock_log_error.assert_called_once()
self.assertIn(
"Azure AI Vision parsing failed",
mock_log_error.call_args[0][0],
)
@override_settings(
REMOTE_OCR_ENGINE="azureai",
REMOTE_OCR_API_KEY="key",
REMOTE_OCR_ENDPOINT="https://endpoint.cognitiveservices.azure.com",
)
def test_supported_mime_types_valid_config(self):
parser = RemoteDocumentParser(uuid.uuid4())
expected_types = {
"application/pdf": ".pdf",
"image/png": ".png",
"image/jpeg": ".jpg",
"image/tiff": ".tiff",
"image/bmp": ".bmp",
"image/gif": ".gif",
"image/webp": ".webp",
}
self.assertEqual(parser.supported_mime_types(), expected_types)
def test_supported_mime_types_invalid_config(self):
parser = get_parser(uuid.uuid4())
self.assertEqual(parser.supported_mime_types(), {})
@override_settings(
REMOTE_OCR_ENGINE=None,
REMOTE_OCR_API_KEY=None,
REMOTE_OCR_ENDPOINT=None,
)
def test_parse_with_invalid_config(self):
parser = get_parser(uuid.uuid4())
parser.parse(self.SAMPLE_FILES / "simple-digital.pdf", "application/pdf")
self.assertEqual(parser.text, "")

39
uv.lock generated
View File

@@ -95,6 +95,34 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl", hash = "sha256:04e9bce696a8d5671ee698005af6e5a9fa15354140a87f4870744604dcdd3ba1", size = 42842, upload-time = "2025-04-16T20:12:14.447Z" },
]
[[package]]
name = "azure-ai-documentintelligence"
version = "1.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "azure-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "isodate", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/44/7b/8115cd713e2caa5e44def85f2b7ebd02a74ae74d7113ba20bdd41fd6dd80/azure_ai_documentintelligence-1.0.2.tar.gz", hash = "sha256:4d75a2513f2839365ebabc0e0e1772f5601b3a8c9a71e75da12440da13b63484", size = 170940 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d9/75/c9ec040f23082f54ffb1977ff8f364c2d21c79a640a13d1c1809e7fd6b1a/azure_ai_documentintelligence-1.0.2-py3-none-any.whl", hash = "sha256:e1fb446abbdeccc9759d897898a0fe13141ed29f9ad11fc705f951925822ed59", size = 106005 },
]
[[package]]
name = "azure-core"
version = "1.33.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "requests", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "six", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/75/aa/7c9db8edd626f1a7d99d09ef7926f6f4fb34d5f9fa00dc394afdfe8e2a80/azure_core-1.33.0.tar.gz", hash = "sha256:f367aa07b5e3005fec2c1e184b882b0b039910733907d001c20fb08ebb8c0eb9", size = 295633 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/07/b7/76b7e144aa53bd206bf1ce34fa75350472c3f69bf30e5c8c18bc9881035d/azure_core-1.33.0-py3-none-any.whl", hash = "sha256:9b5b6d0223a1d38c37500e6971118c1e0f13f54951e6893968b38910bc9cda8f", size = 207071 },
]
[[package]]
name = "babel"
version = "2.17.0"
@@ -1451,6 +1479,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/fc/4e5a141c3f7c7bed550ac1f69e599e92b6be449dd4677ec09f325cad0955/inotifyrecursive-0.3.5-py3-none-any.whl", hash = "sha256:7e5f4a2e1dc2bef0efa3b5f6b339c41fb4599055a2b54909d020e9e932cc8d2f", size = 8009, upload-time = "2020-11-20T12:38:46.981Z" },
]
[[package]]
name = "isodate"
version = "0.7.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320 },
]
[[package]]
name = "jinja2"
version = "3.1.6"
@@ -2118,6 +2155,7 @@ name = "paperless-ngx"
version = "2.20.1"
source = { virtual = "." }
dependencies = [
{ name = "azure-ai-documentintelligence", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "babel", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "bleach", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
{ name = "celery", extra = ["redis"], marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
@@ -2254,6 +2292,7 @@ typing = [
[package.metadata]
requires-dist = [
{ name = "azure-ai-documentintelligence", specifier = ">=1.0.2" },
{ name = "babel", specifier = ">=2.17" },
{ name = "bleach", specifier = "~=6.3.0" },
{ name = "celery", extras = ["redis"], specifier = "~=5.5.1" },