Compare commits

..
Author SHA1 Message Date
stumpylog 08ea8b90a4 Refactor: split views.py into documents/views/ module
documents/views.py suffers the same problem as serialisers.py: a
single 5,395-line file covering every REST resource in the app.
Restructures it into a package, one module per domain area, matching
the same layout used for documents/serialisers/.

paperless/urls.py and paperless_mail/views.py are updated to import
from the new submodules. Test files that imported or mock.patch'd
documents.views or documents.serialisers symbols directly are updated
to point at the correct submodule for both splits. The mypy and
pyrefly baselines are updated to reference the new file paths, and a
stale comment in chat_qa.j2 pointing at the old location of
_get_llm_output_language is corrected.
2026-10-03 14:34:19 -07:00
stumpylog 12fa696c73 Refactor: extract serialisers.py into a structured module
documents/serialisers.py had grown into a single file with every
serialiser for the app, making it hard to navigate and putting
unrelated domains behind one import path.

Moves serialisers into documents/serialisers/ as a package, grouping
them into logical per-domain files instead. paperless_mail/serialisers.py
is updated to import from the new submodules.
2026-10-03 14:03:33 -07:00
248 changed files with 47658 additions and 56229 deletions

No files matched your search

@@ -66,7 +66,7 @@ services:
command: command:
- "gotenberg" - "gotenberg"
- "--chromium-disable-javascript=true" - "--chromium-disable-javascript=true"
- "--chromium-allow-list=^file:///tmp/.*" - "--chromium-allow-list=file:///tmp/.*"
tika: tika:
image: docker.io/apache/tika:3.3.1.0 image: docker.io/apache/tika:3.3.1.0
restart: unless-stopped restart: unless-stopped
+1 -11
View File
@@ -31,19 +31,9 @@ body:
value: | value: |
#### 🤖 Use of AI tools #### 🤖 Use of AI tools
If this report was generated, in whole or in part, by an AI tool or agent you **must** say so using the field below. Failing to clearly disclose this is a violation of our [Code of Conduct](https://github.com/paperless-ngx/paperless-ngx/blob/main/CODE_OF_CONDUCT.md). If this report was generated, in whole or in part, by an AI tool or agent you **must** clearly say so in the description below. Failing to clearly disclose this is a violation of our [Code of Conduct](https://github.com/paperless-ngx/paperless-ngx/blob/main/CODE_OF_CONDUCT.md).
Reports written by an AI agent must describe the _observed behavior only_: what happened, how to reproduce it, logs etc. Do **not** include code analysis, speculation about the root cause, or suggest code fixes. Reports written by an AI agent must describe the _observed behavior only_: what happened, how to reproduce it, logs etc. Do **not** include code analysis, speculation about the root cause, or suggest code fixes.
- type: dropdown
id: ai-usage
attributes:
label: AI usage
description: Was any part of this report written by an AI tool or agent?
options:
- No AI tools were used
- Yes, AI tools helped write this report
validations:
required: true
- type: textarea - type: textarea
id: description id: description
attributes: attributes:
+3 -3
View File
@@ -80,7 +80,7 @@ jobs:
needs: changes needs: changes
if: needs.changes.outputs.backend_changed == 'true' if: needs.changes.outputs.backend_changed == 'true'
name: "Python ${{ matrix.python-version }}" name: "Python ${{ matrix.python-version }}"
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
strategy: strategy:
@@ -114,7 +114,7 @@ jobs:
packages: unpaper tesseract-ocr imagemagick ghostscript poppler-utils packages: unpaper tesseract-ocr imagemagick ghostscript poppler-utils
- name: Configure ImageMagick - name: Configure ImageMagick
run: | run: |
sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-7/policy.xml sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml
- name: Install Python dependencies - name: Install Python dependencies
env: env:
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }} PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
@@ -158,7 +158,7 @@ jobs:
needs: changes needs: changes
if: needs.changes.outputs.backend_changed == 'true' if: needs.changes.outputs.backend_changed == 'true'
name: Check project typing name: Check project typing
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
env: env:
+3 -3
View File
@@ -24,10 +24,10 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- runner: ubuntu-26.04 - runner: ubuntu-24.04
arch: amd64 arch: amd64
platform: linux/amd64 platform: linux/amd64
- runner: ubuntu-26.04-arm - runner: ubuntu-24.04-arm
arch: arm64 arch: arm64
platform: linux/arm64 platform: linux/arm64
runs-on: ${{ matrix.runner }} runs-on: ${{ matrix.runner }}
@@ -163,7 +163,7 @@ jobs:
archive: false archive: false
merge-and-push: merge-and-push:
name: Merge and Push Manifest name: Merge and Push Manifest
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
needs: build-arch needs: build-arch
if: needs.build-arch.outputs.should-push == 'true' if: needs.build-arch.outputs.should-push == 'true'
environment: image-publishing environment: image-publishing
+2 -2
View File
@@ -65,7 +65,7 @@ jobs:
needs: changes needs: changes
if: needs.changes.outputs.docs_changed == 'true' if: needs.changes.outputs.docs_changed == 'true'
name: Build Documentation name: Build Documentation
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- name: Checkout - name: Checkout
@@ -102,7 +102,7 @@ jobs:
name: Deploy Documentation name: Deploy Documentation
needs: [changes, build] needs: [changes, build]
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.docs_changed == 'true' if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.docs_changed == 'true'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
pages: write pages: write
id-token: write id-token: write
+6 -6
View File
@@ -72,7 +72,7 @@ jobs:
needs: changes needs: changes
if: needs.changes.outputs.frontend_changed == 'true' if: needs.changes.outputs.frontend_changed == 'true'
name: Install Dependencies name: Install Dependencies
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
steps: steps:
@@ -104,7 +104,7 @@ jobs:
name: Lint name: Lint
needs: [changes, install-dependencies] needs: [changes, install-dependencies]
if: needs.changes.outputs.frontend_changed == 'true' if: needs.changes.outputs.frontend_changed == 'true'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
steps: steps:
@@ -137,7 +137,7 @@ jobs:
name: "Unit Tests (${{ matrix.shard-index }}/${{ matrix.shard-count }})" name: "Unit Tests (${{ matrix.shard-index }}/${{ matrix.shard-count }})"
needs: [changes, install-dependencies] needs: [changes, install-dependencies]
if: needs.changes.outputs.frontend_changed == 'true' if: needs.changes.outputs.frontend_changed == 'true'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
strategy: strategy:
@@ -188,10 +188,10 @@ jobs:
name: E2E Tests name: E2E Tests
needs: [changes, install-dependencies] needs: [changes, install-dependencies]
if: needs.changes.outputs.frontend_changed == 'true' if: needs.changes.outputs.frontend_changed == 'true'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
container: mcr.microsoft.com/playwright:v1.62.1-resolute container: mcr.microsoft.com/playwright:v1.62.1-noble
env: env:
PLAYWRIGHT_BROWSERS_PATH: /ms-playwright PLAYWRIGHT_BROWSERS_PATH: /ms-playwright
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
@@ -246,7 +246,7 @@ jobs:
name: Frontend Build name: Frontend Build
needs: [changes, unit-tests, e2e-tests] needs: [changes, unit-tests, e2e-tests]
if: needs.changes.outputs.frontend_changed == 'true' if: needs.changes.outputs.frontend_changed == 'true'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
steps: steps:
+5 -5
View File
@@ -14,7 +14,7 @@ permissions: {}
jobs: jobs:
wait-for-docker: wait-for-docker:
name: Wait for Docker Build name: Wait for Docker Build
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
checks: read checks: read
statuses: read statuses: read
@@ -30,7 +30,7 @@ jobs:
build-release: build-release:
name: Build Release name: Build Release
needs: wait-for-docker needs: wait-for-docker
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
steps: steps:
@@ -73,7 +73,7 @@ jobs:
timeout-minutes: 12 timeout-minutes: 12
uses: $/.github/actions/apt-install uses: $/.github/actions/apt-install
with: with:
packages: gettext libleptonica6 packages: gettext liblept5
# ---- Build Documentation ---- # ---- Build Documentation ----
- name: Build documentation - name: Build documentation
env: env:
@@ -145,7 +145,7 @@ jobs:
publish-release: publish-release:
name: Publish Release name: Publish Release
needs: build-release needs: build-release
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
@@ -197,7 +197,7 @@ jobs:
name: Append Changelog name: Append Changelog
needs: publish-release needs: publish-release
if: needs.publish-release.outputs.prerelease == 'false' if: needs.publish-release.outputs.prerelease == 'false'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
+2 -2
View File
@@ -15,7 +15,7 @@ permissions:
jobs: jobs:
zizmor: zizmor:
name: Run zizmor name: Run zizmor
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
actions: read actions: read
@@ -29,7 +29,7 @@ jobs:
uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4 uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
semgrep: semgrep:
name: Semgrep CE name: Semgrep CE
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
container: container:
image: semgrep/semgrep:1.155.0@sha256:cc869c685dcc0fe497c86258da9f205397d8108e56d21a86082ea4886e52784d image: semgrep/semgrep:1.155.0@sha256:cc869c685dcc0fe497c86258da9f205397d8108e56d21a86082ea4886e52784d
if: github.actor != 'dependabot[bot]' if: github.actor != 'dependabot[bot]'
+2 -2
View File
@@ -17,7 +17,7 @@ jobs:
cleanup-images: cleanup-images:
name: Cleanup Image Tags for ${{ matrix.primary-name }} name: Cleanup Image Tags for ${{ matrix.primary-name }}
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
environment: registry-maintenance environment: registry-maintenance
strategy: strategy:
fail-fast: false fail-fast: false
@@ -42,7 +42,7 @@ jobs:
cleanup-untagged-images: cleanup-untagged-images:
name: Cleanup Untagged Images Tags for ${{ matrix.primary-name }} name: Cleanup Untagged Images Tags for ${{ matrix.primary-name }}
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
needs: needs:
- cleanup-images - cleanup-images
environment: registry-maintenance environment: registry-maintenance
+1 -1
View File
@@ -21,7 +21,7 @@ on:
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
actions: read actions: read
contents: read contents: read
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
synchronize-with-crowdin: synchronize-with-crowdin:
name: Crowdin Sync name: Crowdin Sync
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
environment: translation-sync environment: translation-sync
steps: steps:
- name: Checkout - name: Checkout
+8 -25
View File
@@ -7,7 +7,7 @@ jobs:
# Note: peakoss/anti-slop does not support the `issues` event yet (all of its # Note: peakoss/anti-slop does not support the `issues` event yet (all of its
# issue inputs are still commented out upstream), so the checks that the PR Bot # issue inputs are still commented out upstream), so the checks that the PR Bot
# workflow gets from the action are implemented manually here. # workflow gets from the action are implemented manually here.
runs-on: ubuntu-slim runs-on: ubuntu-latest
permissions: permissions:
issues: write issues: write
steps: steps:
@@ -43,12 +43,6 @@ jobs:
const haystack = `${issue.title}\n${issue.body ?? ''}`; const haystack = `${issue.title}\n${issue.body ?? ''}`;
const honeypot = haystack.toUpperCase().includes('ASLOP-PR-VERIFY'); const honeypot = haystack.toUpperCase().includes('ASLOP-PR-VERIFY');
// The form's required "AI usage" dropdown renders as a `### AI usage` section. An agent
// that follows the template trips the honeypot even when it discloses, so only treat
// the honeypot as undisclosed AI use when the reporter did not answer "Yes" here.
const aiUsage = (issue.body ?? '').match(/^###\s+AI usage\s*\n+\s*(.+?)\s*$/m)?.[1] ?? '';
const disclosedAI = aiUsage.toLowerCase().startsWith('yes');
// Issues opened through the form always get the template's default labels. GitHub // Issues opened through the form always get the template's default labels. GitHub
// applies them a second or two *after* creation, so re-read them instead of trusting // applies them a second or two *after* creation, so re-read them instead of trusting
// the webhook payload, and retry before concluding that there are none. // the webhook payload, and retry before concluding that there are none.
@@ -61,30 +55,19 @@ jobs:
if (labels.some((label) => templateLabels.includes(label))) break; if (labels.some((label) => templateLabels.includes(label))) break;
} }
const bypassedTemplate = !labels.some((label) => templateLabels.includes(label)); const bypassedTemplate = !labels.some((label) => templateLabels.includes(label));
core.info( core.info(`Labels: [${labels.join(', ')}], honeypot: ${honeypot}, bypassed template: ${bypassedTemplate}`);
`Labels: [${labels.join(', ')}], honeypot: ${honeypot}, AI usage: "${aiUsage}", ` +
`bypassed template: ${bypassedTemplate}`
);
if (!bypassedTemplate && (disclosedAI || !honeypot)) { if (!honeypot && !bypassedTemplate) {
if (disclosedAI) { core.info('No slop signals found');
core.info('AI use disclosed, labeling only');
await github.rest.issues.addLabels({ ...common, labels: ['ai'] });
} else {
core.info('No slop signals found');
}
return; return;
} }
// The honeypot is only ever tripped deliberately, so that message can name the cause.
// A missing template label only tells us the issue did not come from the form, which // A missing template label only tells us the issue did not come from the form, which
// is reason enough to close it, but not proof of how it was written. It takes priority: // is reason enough to close it, but not proof of how it was written.
// a hand-built body can carry the honeypot *and* a disclosure, and the form message is const body = honeypot
// the only one that is accurate for both. Reaching the honeypot message means the issue
// came from the form without disclosing AI usage, so that message can name the cause.
const body = honeypot && !bypassedTemplate
? 'This issue was automatically closed because it contains a marker that is only visible to ' + ? 'This issue was automatically closed because it contains a marker that is only visible to ' +
'automated tools, which indicates it was generated by an AI agent, but the "AI usage" field does not ' + 'automated tools, which indicates it was generated by an AI agent without being disclosed as such.\n\n' +
'disclose this.\n\n' +
`Please see our [contributing guidelines](${contributing}) and [Code of Conduct](${codeOfConduct}). ` + `Please see our [contributing guidelines](${contributing}) and [Code of Conduct](${codeOfConduct}). ` +
'You are welcome to open a new issue that describes the problem you observed in your own words.' 'You are welcome to open a new issue that describes the problem you observed in your own words.'
: 'This issue was automatically closed because it was not opened using our bug report form. ' + : 'This issue was automatically closed because it was not opened using our bug report form. ' +
+12 -2
View File
@@ -4,7 +4,7 @@ on:
types: [opened] types: [opened]
jobs: jobs:
Anti-slop: Anti-slop:
runs-on: ubuntu-slim runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read
issues: read issues: read
@@ -24,7 +24,7 @@ jobs:
ASLOP-PR-VERIFY ASLOP-PR-VERIFY
pr-bot: pr-bot:
name: Automated PR Bot name: Automated PR Bot
runs-on: ubuntu-slim runs-on: ubuntu-latest
# Runs after Anti-slop so the welcome comment can see whether the PR was closed # Runs after Anti-slop so the welcome comment can see whether the PR was closed
# instead of racing it. Still runs if that job fails, so labeling is not lost. # instead of racing it. Still runs if that job fails, so labeling is not lost.
needs: Anti-slop needs: Anti-slop
@@ -38,6 +38,16 @@ jobs:
uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0 uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Label by size
uses: Gascon1/pr-size-labeler@deff8ed00a76639a7c0f197525bafa3350ba4c36 # v1.3.0
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
xs_label: 'small-change'
xs_diff: '9'
s_label: 'non-trivial'
s_diff: '99999'
fail_if_xl: 'false'
excluded_files: /\.lock$/ /\.txt$/ ^src-ui/pnpm-lock\.yaml$ ^src-ui/messages\.xlf$ ^src/locale/en_US/LC_MESSAGES/django\.po$
- name: Label by PR title - name: Label by PR title
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with: with:
+1 -1
View File
@@ -12,7 +12,7 @@ permissions:
jobs: jobs:
pr_opened_or_reopened: pr_opened_or_reopened:
name: pr_opened_or_reopened name: pr_opened_or_reopened
runs-on: ubuntu-slim runs-on: ubuntu-24.04
permissions: permissions:
# write permission is required for autolabeler # write permission is required for autolabeler
pull-requests: write pull-requests: write
+5 -5
View File
@@ -9,7 +9,7 @@ jobs:
stale: stale:
name: 'Stale' name: 'Stale'
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
issues: write issues: write
pull-requests: write pull-requests: write
@@ -34,7 +34,7 @@ jobs:
lock-threads: lock-threads:
name: 'Lock Old Threads' name: 'Lock Old Threads'
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-26.04 runs-on: ubuntu-24.04
permissions: permissions:
issues: write issues: write
pull-requests: write pull-requests: write
@@ -58,7 +58,7 @@ jobs:
close-answered-discussions: close-answered-discussions:
name: 'Close Answered Discussions' name: 'Close Answered Discussions'
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-slim runs-on: ubuntu-24.04
permissions: permissions:
discussions: write discussions: write
steps: steps:
@@ -117,7 +117,7 @@ jobs:
close-outdated-discussions: close-outdated-discussions:
name: 'Close Outdated Discussions' name: 'Close Outdated Discussions'
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-slim runs-on: ubuntu-24.04
permissions: permissions:
discussions: write discussions: write
steps: steps:
@@ -211,7 +211,7 @@ jobs:
close-unsupported-feature-requests: close-unsupported-feature-requests:
name: 'Close Unsupported Feature Requests' name: 'Close Unsupported Feature Requests'
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-slim runs-on: ubuntu-24.04
permissions: permissions:
discussions: write discussions: write
steps: steps:
+1 -1
View File
@@ -8,7 +8,7 @@ env:
jobs: jobs:
generate-translate-strings: generate-translate-strings:
name: Generate Translation Strings name: Generate Translation Strings
runs-on: ubuntu-26.04 runs-on: ubuntu-latest
environment: translation-sync environment: translation-sync
permissions: permissions:
contents: write contents: write
+351 -351
View File
@@ -410,180 +410,179 @@ src/documents/search/_query.py:0: error: Argument 3 to "Term" has incompatible t
src/documents/search/_query.py:0: error: Argument 3 to "Term" has incompatible type "**dict[str, int | None]"; expected "bool" [arg-type] src/documents/search/_query.py:0: error: Argument 3 to "Term" has incompatible type "**dict[str, int | None]"; expected "bool" [arg-type]
src/documents/search/_query.py:0: error: Unexpected keyword argument "children" for "Node" [call-arg] src/documents/search/_query.py:0: error: Unexpected keyword argument "children" for "Node" [call-arg]
src/documents/search/_schema.py:0: error: Redundant cast to "Path" [redundant-cast] src/documents/search/_schema.py:0: error: Redundant cast to "Path" [redundant-cast]
src/documents/search/_schema.py:0: error: Unexpected keyword argument "fast" for "add_json_field" of "SchemaBuilder" [call-arg] src/documents/serialisers/base.py:0: error: "type[_MT?]" has no attribute "_meta" [attr-defined]
src/documents/serialisers.py:0: error: "type[_MT?]" has no attribute "_meta" [attr-defined] src/documents/serialisers/base.py:0: error: "type[_MT?]" has no attribute "objects" [attr-defined]
src/documents/serialisers.py:0: error: "type[_MT?]" has no attribute "objects" [attr-defined] src/documents/serialisers/base.py:0: error: "type[_MT?]" has no attribute "objects" [attr-defined]
src/documents/serialisers.py:0: error: "type[_MT?]" has no attribute "objects" [attr-defined] src/documents/serialisers/base.py:0: error: "type[_MT?]" has no attribute "objects" [attr-defined]
src/documents/serialisers.py:0: error: "type[_MT?]" has no attribute "objects" [attr-defined] src/documents/serialisers/base.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument "choices" to "ChoiceField" has incompatible type "type[FieldDataType]"; expected "Sequence[Any]" [arg-type] src/documents/serialisers/base.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument "default" to "MultipleChoiceField" has incompatible type "set[DocumentSource]"; expected "set[str | int] | set[str] | set[int] | Callable[[], set[str | int] | set[str] | set[int]] | _Empty | None" [arg-type] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument 1 of "get_value" is incompatible with supertype "rest_framework.fields.Field"; supertype defines the argument type as "Mapping[str, Any]" [override] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument 1 of "update" is incompatible with supertype "rest_framework.serializers.BaseSerializer"; supertype defines the argument type as "dict[str, Any]" [override] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument 1 to "__get__" of "BaseManager" has incompatible type "PrimaryKeyRelatedField[Any]"; expected "Options[Any] | None" [arg-type] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument 1 to "get_value_field_name" of "CustomFieldInstance" has incompatible type "str"; expected "FieldDataType" [arg-type] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument 1 to "int" has incompatible type "Any | Collection[str]"; expected "str | Buffer | SupportsInt | SupportsIndex" [arg-type] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Argument 1 to "list" has incompatible type "QuerySet[Document, TypedDict({'id': int, 'title': str, 'deleted_at': datetime | None})]"; expected "Iterable[dict[str, Any]]" [arg-type] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Expected iterable as variadic argument [misc] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Item "Field[Any, Any, Any, Any]" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Item "None" of "Any | None" has no attribute "name" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Item "None" of "Any | None" has no attribute "pk" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "context" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Item "list[str]" of "Any | list[str]" has no attribute "values_list" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Missing type arguments for generic type "Iterable" [type-arg]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Missing type arguments for generic type "dict" [type-arg]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Need type annotation for "permissions_dict" [var-annotated]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/base.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any] | Any") [index]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Incompatible types in assignment (expression has type "type[Correspondent]", variable has type "type[Tag] | None") [assignment]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Incompatible types in assignment (expression has type "type[DocumentType]", variable has type "type[Tag] | None") [assignment]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Incompatible types in assignment (expression has type "type[StoragePath]", variable has type "type[Tag] | None") [assignment]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/bulk_edit.py:0: error: Missing type arguments for generic type "dict" [type-arg]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Argument 1 of "update" is incompatible with supertype "rest_framework.serializers.BaseSerializer"; supertype defines the argument type as "dict[str, Any]" [override]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Incompatible types in assignment (expression has type "type[SearchResultListSerializer]", base class "Meta" defined the type as "type[OwnedObjectListSerializer]") [assignment]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Item "Field[Any, Any, Any, Any]" of "Field[Any, Any, Any, Any] | None" has no attribute "fetch_documents" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/serialisers/documents.py:0: error: Item "Field[Any, Any, Any, Any]" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "context" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "context" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "fetch_documents" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Skipping analyzing "auditlog.context": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any] | Any") [index]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any] | Any") [index]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/documents.py:0: error: Value of type "Any | None" is not indexable [index]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Argument "choices" to "ChoiceField" has incompatible type "type[FieldDataType]"; expected "Sequence[Any]" [arg-type]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Argument 1 of "get_value" is incompatible with supertype "rest_framework.fields.Field"; supertype defines the argument type as "Mapping[str, Any]" [override]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Argument 1 to "__get__" of "BaseManager" has incompatible type "PrimaryKeyRelatedField[Any]"; expected "Options[Any] | None" [arg-type]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Argument 1 to "get_value_field_name" of "CustomFieldInstance" has incompatible type "str"; expected "FieldDataType" [arg-type]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Expected iterable as variadic argument [misc]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Incompatible types in assignment (expression has type "PrimaryKeyRelatedField[Tag]", base class "Field" defined the type as "BaseSerializer[Any]") [assignment]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Incompatible types in assignment (expression has type "Sequence[str] | tuple[Lower]", variable has type "Sequence[str] | None") [assignment]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Item "None" of "CustomField | None" has no attribute "name" [union-attr]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Missing type arguments for generic type "Field" [type-arg]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Missing type arguments for generic type "dict" [type-arg]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Need type annotation for "document" [var-annotated]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any]") [index]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/metadata.py:0: error: Value of type "Any | None" is not indexable [index]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/saved_views.py:0: error: Argument 1 to "int" has incompatible type "Any | Collection[str]"; expected "str | Buffer | SupportsInt | SupportsIndex" [arg-type]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/saved_views.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/saved_views.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/serialisers/saved_views.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Incompatible types in assignment (expression has type "PrimaryKeyRelatedField[Tag]", base class "Field" defined the type as "BaseSerializer[Any]") [assignment] src/documents/serialisers/saved_views.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Incompatible types in assignment (expression has type "Sequence[str] | tuple[Lower]", variable has type "Sequence[str] | None") [assignment] src/documents/serialisers/saved_views.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Incompatible types in assignment (expression has type "WorkflowActionWebhookSerializer", variable has type "WorkflowActionEmailSerializer") [assignment] src/documents/serialisers/saved_views.py:0: error: Value of type "Match[str] | None" is not indexable [index]
src/documents/serialisers.py:0: error: Incompatible types in assignment (expression has type "type[Correspondent]", variable has type "type[Tag] | None") [assignment] src/documents/serialisers/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Incompatible types in assignment (expression has type "type[DocumentType]", variable has type "type[Tag] | None") [assignment] src/documents/serialisers/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Incompatible types in assignment (expression has type "type[SearchResultListSerializer]", base class "Meta" defined the type as "type[OwnedObjectListSerializer]") [assignment] src/documents/serialisers/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Incompatible types in assignment (expression has type "type[StoragePath]", variable has type "type[Tag] | None") [assignment] src/documents/serialisers/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Item "Field[Any, Any, Any, Any]" of "Field[Any, Any, Any, Any] | None" has no attribute "fetch_documents" [union-attr] src/documents/serialisers/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Item "Field[Any, Any, Any, Any]" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr] src/documents/serialisers/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Item "Field[Any, Any, Any, Any]" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr] src/documents/serialisers/sharing.py:0: error: Need type annotation for "documents" [var-annotated]
src/documents/serialisers.py:0: error: Item "None" of "Any | None" has no attribute "name" [union-attr] src/documents/serialisers/system.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Item "None" of "Any | None" has no attribute "pk" [union-attr] src/documents/serialisers/system.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Item "None" of "CustomField | None" has no attribute "name" [union-attr] src/documents/serialisers/tasks.py:0: error: Argument 1 to "list" has incompatible type "QuerySet[Document, TypedDict({'id': int, 'title': str, 'deleted_at': datetime | None})]"; expected "Iterable[dict[str, Any]]" [arg-type]
src/documents/serialisers.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "context" [union-attr] src/documents/serialisers/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "context" [union-attr] src/documents/serialisers/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "context" [union-attr] src/documents/serialisers/tasks.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "fetch_documents" [union-attr] src/documents/serialisers/tasks.py:0: error: No overload variant of "get" of "dict" matches argument types "str", "str" [call-overload]
src/documents/serialisers.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr] src/documents/serialisers/tasks.py:0: error: No overload variant of "get" of "dict" matches argument types "str", "str" [call-overload]
src/documents/serialisers.py:0: error: Item "None" of "Field[Any, Any, Any, Any] | None" has no attribute "get_shared_object_pks" [union-attr] src/documents/serialisers/tasks.py:0: error: No overload variant of "get" of "dict" matches argument types "str", "str" [call-overload]
src/documents/serialisers.py:0: error: Item "list[str]" of "Any | list[str]" has no attribute "values_list" [union-attr] src/documents/serialisers/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Missing type arguments for generic type "Field" [type-arg] src/documents/serialisers/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Missing type arguments for generic type "Iterable" [type-arg] src/documents/serialisers/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Missing type arguments for generic type "dict" [type-arg] src/documents/serialisers/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Missing type arguments for generic type "dict" [type-arg] src/documents/serialisers/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Missing type arguments for generic type "dict" [type-arg] src/documents/serialisers/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Need type annotation for "document" [var-annotated] src/documents/serialisers/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Need type annotation for "documents" [var-annotated] src/documents/serialisers/workflows.py:0: error: Argument "default" to "MultipleChoiceField" has incompatible type "set[DocumentSource]"; expected "set[str | int] | set[str] | set[int] | Callable[[], set[str | int] | set[str] | set[int]] | _Empty | None" [arg-type]
src/documents/serialisers.py:0: error: Need type annotation for "permissions_dict" [var-annotated] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: No overload variant of "get" of "dict" matches argument types "str", "str" [call-overload] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: No overload variant of "get" of "dict" matches argument types "str", "str" [call-overload] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: No overload variant of "get" of "dict" matches argument types "str", "str" [call-overload] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Skipping analyzing "auditlog.context": module is installed, but missing library stubs or py.typed marker [import-untyped] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any] | Any") [index] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any] | Any") [index] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any] | Any") [index] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Unsupported target for indexed assignment ("Mapping[str, Any]") [index] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Value of type "Any | None" is not indexable [index] src/documents/serialisers/workflows.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/serialisers.py:0: error: Value of type "Any | None" is not indexable [index] src/documents/serialisers/workflows.py:0: error: Incompatible types in assignment (expression has type "WorkflowActionWebhookSerializer", variable has type "WorkflowActionEmailSerializer") [assignment]
src/documents/serialisers.py:0: error: Value of type "Match[str] | None" is not indexable [index]
src/documents/signals/handlers.py:0: error: "BaseDatabaseWrapper" has no attribute "close_pool" [attr-defined] src/documents/signals/handlers.py:0: error: "BaseDatabaseWrapper" has no attribute "close_pool" [attr-defined]
src/documents/signals/handlers.py:0: error: "BaseDatabaseWrapper" has no attribute "close_pool" [attr-defined] src/documents/signals/handlers.py:0: error: "BaseDatabaseWrapper" has no attribute "close_pool" [attr-defined]
src/documents/signals/handlers.py:0: error: "Task[[int, int], Any]" has no attribute "delay_on_commit" [attr-defined] src/documents/signals/handlers.py:0: error: "Task[[int, int], Any]" has no attribute "delay_on_commit" [attr-defined]
@@ -1525,180 +1524,181 @@ src/documents/utils.py:0: error: Incompatible types in assignment (expression ha
src/documents/utils.py:0: error: Missing type arguments for generic type "CompletedProcess" [type-arg] src/documents/utils.py:0: error: Missing type arguments for generic type "CompletedProcess" [type-arg]
src/documents/validators.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/validators.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/versioning.py:0: error: Missing type arguments for generic type "Prefetch" [type-arg] src/documents/versioning.py:0: error: Missing type arguments for generic type "Prefetch" [type-arg]
src/documents/views.py:0: error: "BulkPermissionMixin" has no attribute "filter_queryset" [attr-defined] src/documents/views/base.py:0: error: "BulkPermissionMixin" has no attribute "filter_queryset" [attr-defined]
src/documents/views.py:0: error: "BulkPermissionMixin" has no attribute "get_queryset" [attr-defined] src/documents/views/base.py:0: error: "BulkPermissionMixin" has no attribute "get_queryset" [attr-defined]
src/documents/views.py:0: error: "BulkPermissionMixin" has no attribute "queryset" [attr-defined] src/documents/views/base.py:0: error: "BulkPermissionMixin" has no attribute "queryset" [attr-defined]
src/documents/views.py:0: error: "BulkPermissionMixin" has no attribute "queryset" [attr-defined] src/documents/views/base.py:0: error: "BulkPermissionMixin" has no attribute "queryset" [attr-defined]
src/documents/views.py:0: error: "Sequence[_SupportsHasPermission]" has no attribute "append" [attr-defined] src/documents/views/base.py:0: error: "get_serializer_context" undefined in superclass [misc]
src/documents/views.py:0: error: "get_serializer_context" undefined in superclass [misc] src/documents/views/base.py:0: error: "type[Model]" has no attribute "objects" [attr-defined]
src/documents/views.py:0: error: "object" has no attribute "apply_async" [attr-defined] src/documents/views/base.py:0: error: Argument "user" to "_has_document_permissions" of "DocumentOperationPermissionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type]
src/documents/views.py:0: error: "type[DocumentFilterSet]" has no attribute "declared_filters" [attr-defined] src/documents/views/base.py:0: error: Argument "user" to "_resolve_document_ids" of "DocumentSelectionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type]
src/documents/views.py:0: error: "type[Model]" has no attribute "objects" [attr-defined] src/documents/views/base.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument "filename" to "FileResponse" has incompatible type "str | Any | None"; expected "str" [arg-type] src/documents/views/base.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument "path" to "EmailAttachment" has incompatible type "Path | None"; expected "Path" [arg-type] src/documents/views/base.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument "user" to "_has_document_permissions" of "DocumentOperationPermissionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type] src/documents/views/base.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument "user" to "_has_document_permissions" of "DocumentOperationPermissionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type] src/documents/views/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument "user" to "_resolve_document_ids" of "DocumentSelectionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type] src/documents/views/base.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument "user" to "_resolve_document_ids" of "DocumentSelectionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type] src/documents/views/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/views.py:0: error: Argument 1 to "TaskSummarySerializer" has incompatible type "QuerySet[PaperlessTask@AnnotatedWith[TypedDict({'total_count': int, 'pending_count': int, 'success_count': int, 'failure_count': int, 'avg_duration_seconds': Any, 'avg_wait_time_seconds': Any, 'last_run': Any, 'last_success': Any, 'last_failure': Any})], TypedDict({'task_type': str, 'total_count': Any, 'pending_count': Any, 'success_count': Any, 'failure_count': Any, 'avg_duration_seconds': Any, 'avg_wait_time_seconds': Any, 'last_run': Any, 'last_success': Any, 'last_failure': Any})]"; expected "dict[str, Any] | None" [arg-type] src/documents/views/base.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/views.py:0: error: Argument 1 to "int" has incompatible type "Any | Collection[str]"; expected "str | Buffer | SupportsInt | SupportsIndex" [arg-type] src/documents/views/base.py:0: error: Missing type arguments for generic type "list" [type-arg]
src/documents/views.py:0: error: Argument 1 to "int" has incompatible type "Any | Collection[str]"; expected "str | Buffer | SupportsInt | SupportsIndex" [arg-type] src/documents/views/bulk_edit.py:0: error: Argument "user" to "_has_document_permissions" of "DocumentOperationPermissionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type]
src/documents/views.py:0: error: Argument 1 to "paginate_queryset" of "GenericAPIView" has incompatible type "TantivyRelevanceList"; expected "QuerySet[Any, _MT_co] | Sequence[_MT_co]" [arg-type] src/documents/views/bulk_edit.py:0: error: Argument "user" to "_resolve_document_ids" of "DocumentSelectionMixin" has incompatible type "User | AnonymousUser"; expected "User" [arg-type]
src/documents/views.py:0: error: Argument 1 to "permitted_document_ids" has incompatible type "User | AnonymousUser"; expected "User | None" [arg-type] src/documents/views/bulk_edit.py:0: error: Argument 1 to "int" has incompatible type "Any | Collection[str]"; expected "str | Buffer | SupportsInt | SupportsIndex" [arg-type]
src/documents/views.py:0: error: Argument 1 to "permitted_object_ids" has incompatible type "User | AnonymousUser"; expected "User | None" [arg-type] src/documents/views/bulk_edit.py:0: error: Argument 1 to "permitted_object_ids" has incompatible type "User | AnonymousUser"; expected "User | None" [arg-type]
src/documents/views.py:0: error: Argument 2 to "match_correspondents" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument 2 to "match_document_types" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument 2 to "match_storage_paths" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument 2 to "match_tags" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Argument 3 to "autocomplete" of "TantivyBackend" has incompatible type "User | AnonymousUser | None"; expected "AbstractUser | None" [arg-type] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Dict entry 0 has incompatible type "str": "bool"; expected "str": "str" [dict-item] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/bulk_edit.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/bulk_edit.py:0: error: Incompatible types in assignment (expression has type "type[ArchiveOnlyStrategy]", variable has type "type[OriginalAndArchiveStrategy]") [assignment]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/bulk_edit.py:0: error: Incompatible types in assignment (expression has type "type[OriginalsOnlyStrategy]", variable has type "type[OriginalAndArchiveStrategy]") [assignment]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/bulk_edit.py:0: error: Skipping analyzing "auditlog.models": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/chat.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: "type[DocumentFilterSet]" has no attribute "declared_filters" [attr-defined]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Argument "path" to "EmailAttachment" has incompatible type "Path | None"; expected "Path" [arg-type]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Argument 1 to "paginate_queryset" of "GenericAPIView" has incompatible type "TantivyRelevanceList"; expected "QuerySet[Any, _MT_co] | Sequence[_MT_co]" [arg-type]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Argument 2 to "match_correspondents" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Argument 2 to "match_document_types" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Argument 2 to "match_storage_paths" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Argument 2 to "match_tags" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Incompatible types in assignment (expression has type "ClassificationSuggestions", variable has type "dict[Any, Any]") [assignment]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Item "BasePagination" of "BasePagination | None" has no attribute "get_page_size" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Item "BasePagination" of "BasePagination | None" has no attribute "page_size" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Item "None" of "BasePagination | None" has no attribute "get_page_size" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Item "None" of "BasePagination | None" has no attribute "page_size" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Missing positional argument "request" in call to "email_documents" [call-arg]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Missing type arguments for generic type "list" [type-arg]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Missing type arguments for generic type "list" [type-arg]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Missing type arguments for generic type "list" [type-arg]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Need type annotation for "doc" [var-annotated]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Need type annotation for "doc" [var-annotated]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: No overload variant of "prefetch_related" of "QuerySet" matches argument type "list[object]" [call-overload]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Skipping analyzing "auditlog.models": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Skipping analyzing "langdetect": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/documents.py:0: error: Unsupported operand types for + ("None" and "int") [operator]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/index.py:0: error: Argument "filename" to "FileResponse" has incompatible type "str | Any | None"; expected "str" [arg-type]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/index.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/index.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/index.py:0: error: Item "AnonymousUser" of "User | AnonymousUser" has no attribute "get_full_name" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/index.py:0: error: Item "None" of "Any | None" has no attribute "get" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/index.py:0: error: Item "None" of "Any | None" has no attribute "get" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/index.py:0: error: Item "None" of "ApplicationConfiguration | None" has no attribute "app_logo" [union-attr]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/logs.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/logs.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Argument 1 to "int" has incompatible type "Any | Collection[str]"; expected "str | Buffer | SupportsInt | SupportsIndex" [arg-type]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Incompatible types in assignment (expression has type "tuple[type[IsAuthenticated], type[ViewDocumentsPermissions]]", variable has type "tuple[type[IsAuthenticated], type[PaperlessObjectPermissions]]") [assignment]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/metadata.py:0: error: Need type annotation for "children_map" (hint: "children_map: dict[<type>, <type>] = ...") [var-annotated]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/search.py:0: error: Argument 3 to "autocomplete" of "TantivyBackend" has incompatible type "User | AnonymousUser | None"; expected "AbstractUser | None" [arg-type]
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/views/search.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/views/search.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/views/search.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/views/search.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/views/search.py:0: error: Incompatible types in assignment (expression has type "QuerySet[Document, Document]", variable has type "list[Any]") [assignment]
src/documents/views.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/views/search.py:0: error: Need type annotation for "docs" (hint: "docs: list[<type>] = ...") [var-annotated]
src/documents/views.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/views/search.py:0: error: Value of type "Iterable[Any]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "Any | None", variable has type "dict[Any, Any]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Any]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "ClassificationSuggestions", variable has type "dict[Any, Any]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Any]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "QuerySet[Document, Document]", variable has type "list[Any]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Any]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "bool", target has type "dict[str, str]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Any]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "bool", target has type "dict[str, str]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Any]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "bool", target has type "dict[str, str]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Any]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "int", target has type "dict[str, str]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[CustomField]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "str | None", target has type "dict[str, str]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Group]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "str | None", target has type "dict[str, str]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[User]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment] src/documents/views/search.py:0: error: Value of type "Iterable[Workflow]" is not indexable [index]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment] src/documents/views/sharing.py:0: error: "Sequence[_SupportsHasPermission]" has no attribute "append" [attr-defined]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment] src/documents/views/sharing.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment] src/documents/views/sharing.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment] src/documents/views/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "tuple[type[IsAuthenticated], type[ViewDocumentsPermissions]]", variable has type "tuple[type[IsAuthenticated], type[PaperlessObjectPermissions]]") [assignment] src/documents/views/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "type[ArchiveOnlyStrategy]", variable has type "type[OriginalAndArchiveStrategy]") [assignment] src/documents/views/sharing.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "type[DocumentSerializer]", variable has type "type[TrashSerializer]") [assignment] src/documents/views/sharing.py:0: error: Missing type arguments for generic type "GenericViewSet" [type-arg]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "type[OriginalsOnlyStrategy]", variable has type "type[OriginalAndArchiveStrategy]") [assignment] src/documents/views/sharing.py:0: error: Need type annotation for "authentication_classes" (hint: "authentication_classes: list[<type>] = ...") [var-annotated]
src/documents/views.py:0: error: Item "AnonymousUser" of "User | AnonymousUser" has no attribute "get_full_name" [union-attr] src/documents/views/sharing.py:0: error: Need type annotation for "permission_classes" (hint: "permission_classes: list[<type>] = ...") [var-annotated]
src/documents/views.py:0: error: Item "BasePagination" of "BasePagination | None" has no attribute "get_page_size" [union-attr] src/documents/views/system.py:0: error: Argument 1 to "permitted_document_ids" has incompatible type "User | AnonymousUser"; expected "User | None" [arg-type]
src/documents/views.py:0: error: Item "BasePagination" of "BasePagination | None" has no attribute "page_size" [union-attr] src/documents/views/system.py:0: error: Dict entry 0 has incompatible type "str": "bool"; expected "str": "str" [dict-item]
src/documents/views.py:0: error: Item "None" of "Any | None" has no attribute "get" [union-attr] src/documents/views/system.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Item "None" of "Any | None" has no attribute "get" [union-attr] src/documents/views/system.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Item "None" of "ApplicationConfiguration | None" has no attribute "app_logo" [union-attr] src/documents/views/system.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Item "None" of "BasePagination | None" has no attribute "get_page_size" [union-attr] src/documents/views/system.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Item "None" of "BasePagination | None" has no attribute "page_size" [union-attr] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "Any | None", variable has type "dict[Any, Any]") [assignment]
src/documents/views.py:0: error: Missing positional argument "request" in call to "email_documents" [call-arg] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "bool", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Missing type arguments for generic type "GenericViewSet" [type-arg] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "bool", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Missing type arguments for generic type "list" [type-arg] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "bool", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Missing type arguments for generic type "list" [type-arg] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "int", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Missing type arguments for generic type "list" [type-arg] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "str | None", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Missing type arguments for generic type "list" [type-arg] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "str | None", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Need type annotation for "authentication_classes" (hint: "authentication_classes: list[<type>] = ...") [var-annotated] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Need type annotation for "children_map" (hint: "children_map: dict[<type>, <type>] = ...") [var-annotated] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Need type annotation for "doc" [var-annotated] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Need type annotation for "doc" [var-annotated] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Need type annotation for "docs" (hint: "docs: list[<type>] = ...") [var-annotated] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "str", target has type "dict[str, str]") [assignment]
src/documents/views.py:0: error: Need type annotation for "permission_classes" (hint: "permission_classes: list[<type>] = ...") [var-annotated] src/documents/views/system.py:0: error: Incompatible types in assignment (expression has type "type[DocumentSerializer]", variable has type "type[TrashSerializer]") [assignment]
src/documents/views.py:0: error: Need type annotation for "ui_settings" (hint: "ui_settings: dict[<type>, <type>] = ...") [var-annotated] src/documents/views/system.py:0: error: Need type annotation for "ui_settings" (hint: "ui_settings: dict[<type>, <type>] = ...") [var-annotated]
src/documents/views.py:0: error: No overload variant of "prefetch_related" of "QuerySet" matches argument type "list[object]" [call-overload] src/documents/views/tasks.py:0: error: "object" has no attribute "apply_async" [attr-defined]
src/documents/views.py:0: error: Skipping analyzing "auditlog.models": module is installed, but missing library stubs or py.typed marker [import-untyped] src/documents/views/tasks.py:0: error: Argument 1 to "TaskSummarySerializer" has incompatible type "QuerySet[PaperlessTask@AnnotatedWith[TypedDict({'total_count': int, 'pending_count': int, 'success_count': int, 'failure_count': int, 'avg_duration_seconds': Any, 'avg_wait_time_seconds': Any, 'last_run': Any, 'last_success': Any, 'last_failure': Any})], TypedDict({'task_type': str, 'total_count': Any, 'pending_count': Any, 'success_count': Any, 'failure_count': Any, 'avg_duration_seconds': Any, 'avg_wait_time_seconds': Any, 'last_run': Any, 'last_success': Any, 'last_failure': Any})]"; expected "dict[str, Any] | None" [arg-type]
src/documents/views.py:0: error: Skipping analyzing "langdetect": module is installed, but missing library stubs or py.typed marker [import-untyped] src/documents/views/tasks.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Unsupported operand types for + ("None" and "int") [operator] src/documents/views/tasks.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Any]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Any]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Any]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Any]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Any]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Any]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Any]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[CustomField]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Group]" is not indexable [index] src/documents/views/tasks.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[User]" is not indexable [index] src/documents/views/upload.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Value of type "Iterable[Workflow]" is not indexable [index] src/documents/views/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views/workflows.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/workflows/actions.py:0: error: Function is missing a return type annotation [no-untyped-def] src/documents/workflows/actions.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/workflows/actions.py:0: error: Function is missing a type annotation [no-untyped-def] src/documents/workflows/actions.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/workflows/actions.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def] src/documents/workflows/actions.py:0: error: Function is missing a type annotation for one or more parameters [no-untyped-def]
@@ -2145,9 +2145,9 @@ src/paperless_ai/ai_classifier.py:0: error: Argument 1 to "parse_ai_response" ha
src/paperless_ai/ai_classifier.py:0: error: Incompatible types in assignment (expression has type "Any | None", variable has type "str") [assignment] src/paperless_ai/ai_classifier.py:0: error: Incompatible types in assignment (expression has type "Any | None", variable has type "str") [assignment]
src/paperless_ai/ai_classifier.py:0: error: Missing type arguments for generic type "dict" [type-arg] src/paperless_ai/ai_classifier.py:0: error: Missing type arguments for generic type "dict" [type-arg]
src/paperless_ai/ai_classifier.py:0: error: Missing type arguments for generic type "dict" [type-arg] src/paperless_ai/ai_classifier.py:0: error: Missing type arguments for generic type "dict" [type-arg]
src/paperless_ai/ai_classifier.py:0: error: TypedDict key must be a string literal; expected one of ("correspondents", "dates", "document_types", "storage_paths", "tags", ...) [literal-required] src/paperless_ai/ai_classifier.py:0: error: TypedDict key must be a string literal; expected one of ("title", "tags", "correspondents", "document_types", "storage_paths", ...) [literal-required]
src/paperless_ai/ai_classifier.py:0: error: TypedDict key must be a string literal; expected one of ("correspondents", "dates", "document_types", "storage_paths", "tags", ...) [literal-required] src/paperless_ai/ai_classifier.py:0: error: TypedDict key must be a string literal; expected one of ("title", "tags", "correspondents", "document_types", "storage_paths", ...) [literal-required]
src/paperless_ai/ai_classifier.py:0: error: TypedDict key must be a string literal; expected one of ("correspondents", "dates", "document_types", "storage_paths", "tags", ...) [literal-required] src/paperless_ai/ai_classifier.py:0: error: TypedDict key must be a string literal; expected one of ("title", "tags", "correspondents", "document_types", "storage_paths", ...) [literal-required]
src/paperless_ai/base_model.py:0: error: Invalid index type "str | None" for "dict[str, FieldInfo]"; expected type "str" [index] src/paperless_ai/base_model.py:0: error: Invalid index type "str | None" for "dict[str, FieldInfo]"; expected type "str" [index]
src/paperless_ai/chat.py:0: error: Dict entry 1 has incompatible type "str": "str | Any | None"; expected "str": "int | str" [dict-item] src/paperless_ai/chat.py:0: error: Dict entry 1 has incompatible type "str": "str | Any | None"; expected "str": "int | str" [dict-item]
src/paperless_ai/chat.py:0: error: Function is missing a return type annotation [no-untyped-def] src/paperless_ai/chat.py:0: error: Function is missing a return type annotation [no-untyped-def]
+357 -364
View File
@@ -896,240 +896,233 @@
"concise_description": "Argument `FieldRef | None` is not assignable to parameter `field` with type `FieldRef` in function `whoosh_compat.ast.Fuzzy.__init__`", "concise_description": "Argument `FieldRef | None` is not assignable to parameter `field` with type `FieldRef` in function `whoosh_compat.ast.Fuzzy.__init__`",
"severity": "error" "severity": "error"
}, },
{
"column": 17,
"path": "src/documents/search/_schema.py",
"name": "unexpected-keyword",
"concise_description": "Unexpected keyword argument `fast` in function `tantivy.tantivy.SchemaBuilder.add_json_field`",
"severity": "error"
},
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/base.py",
"name": "bad-override-param-name", "name": "bad-override-param-name",
"concise_description": "Class member `MatchingModelSerializer.validate` overrides parent class `ModelSerializer` in an inconsistent manner", "concise_description": "Class member `MatchingModelSerializer.validate` overrides parent class `ModelSerializer` in an inconsistent manner",
"severity": "error" "severity": "error"
}, },
{ {
"column": 62, "column": 62,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/base.py",
"name": "unsupported-operation", "name": "unsupported-operation",
"concise_description": "Cannot set item in `dict[str, QuerySet[User, User]]`", "concise_description": "Cannot set item in `dict[str, QuerySet[User, User]]`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 17, "column": 17,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `list` has no attribute `values_list`", "concise_description": "Object of class `list` has no attribute `values_list`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/base.py",
"name": "bad-override-param-name", "name": "bad-override-param-name",
"concise_description": "Class member `OwnedObjectListSerializer.to_representation` overrides parent class `ListSerializer` in an inconsistent manner", "concise_description": "Class member `OwnedObjectListSerializer.to_representation` overrides parent class `ListSerializer` in an inconsistent manner",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `context`", "concise_description": "Object of class `NoneType` has no attribute `context`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 51, "column": 51,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of type `BaseSerializer[Unknown] | Field[Unknown, Unknown, Unknown, Unknown] | None` has no attribute `get_shared_object_pks`", "concise_description": "Object of type `BaseSerializer[Unknown] | Field[Unknown, Unknown, Unknown, Unknown] | None` has no attribute `get_shared_object_pks`",
"severity": "error" "severity": "error"
}, },
{
"column": 14,
"path": "src/documents/serialisers.py",
"name": "bad-assignment",
"concise_description": "`ManyRelatedField | RelatedField[@_, @_, Any]` is not assignable to attribute `parent` with type `BaseSerializer[Unknown]`",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/serialisers.py",
"name": "unsupported-operation",
"concise_description": "Cannot set item in `Mapping[str, Any]`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/serialisers.py",
"name": "bad-override-param-name",
"concise_description": "Class member `TagSerializer.validate` overrides parent class `MatchingModelSerializer` in an inconsistent manner",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/serialisers.py",
"name": "bad-argument-type",
"concise_description": "Argument `type[CustomField.FieldDataType]` is not assignable to parameter `choices` with type `Sequence[Any]` in function `rest_framework.fields.ChoiceField.__init__`",
"severity": "error"
},
{ {
"column": 28, "column": 28,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/base.py",
"name": "bad-assignment", "name": "bad-assignment",
"concise_description": "`Unknown | None` is not assignable to attribute `method_name` with type `str`", "concise_description": "`Unknown | None` is not assignable to attribute `method_name` with type `str`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 13, "column": 7,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/bulk_edit.py",
"name": "bad-argument-type", "name": "invalid-inheritance",
"concise_description": "Argument `str` is not assignable to parameter `data_type` with type `CustomField.FieldDataType` in function `documents.models.CustomFieldInstance.get_value_field_name`", "concise_description": "Class `BulkEditSerializer` has inconsistent type arguments for base class `Field`: `Field[Any, Any, Any, dict[str, Any]]` and `Field[Any, Any, Any, dict[str, list[int]]]`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/serialisers.py",
"name": "bad-override-param-name",
"concise_description": "Class member `CustomFieldInstanceSerializer.get_value` overrides parent class `ModelSerializer` in an inconsistent manner",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/serialisers.py",
"name": "bad-override-param-name",
"concise_description": "Class member `CustomFieldInstanceSerializer.validate` overrides parent class `ModelSerializer` in an inconsistent manner",
"severity": "error"
},
{
"column": 34,
"path": "src/documents/serialisers.py",
"name": "unsupported-operation",
"concise_description": "`None` is not subscriptable",
"severity": "error" "severity": "error"
}, },
{ {
"column": 30, "column": 30,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "unsupported-operation", "name": "unsupported-operation",
"concise_description": "`None` is not subscriptable", "concise_description": "`None` is not subscriptable",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "bad-override-param-name", "name": "bad-override-param-name",
"concise_description": "Class member `SearchResultListSerializer.to_representation` overrides parent class `ListSerializer` in an inconsistent manner", "concise_description": "Class member `SearchResultListSerializer.to_representation` overrides parent class `ListSerializer` in an inconsistent manner",
"severity": "error" "severity": "error"
}, },
{ {
"column": 21, "column": 21,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of type `BaseSerializer[Unknown] | Field[Unknown, Unknown, Unknown, Unknown] | None` has no attribute `fetch_documents`", "concise_description": "Object of type `BaseSerializer[Unknown] | Field[Unknown, Unknown, Unknown, Unknown] | None` has no attribute `fetch_documents`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `context`", "concise_description": "Object of class `NoneType` has no attribute `context`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `context`", "concise_description": "Object of class `NoneType` has no attribute `context`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 51, "column": 51,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of type `BaseSerializer[Unknown] | Field[Unknown, Unknown, Unknown, Unknown] | None` has no attribute `get_shared_object_pks`", "concise_description": "Object of type `BaseSerializer[Unknown] | Field[Unknown, Unknown, Unknown, Unknown] | None` has no attribute `get_shared_object_pks`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "bad-override-param-name", "name": "bad-override-param-name",
"concise_description": "Class member `SearchResultSerializer.to_representation` overrides parent class `DocumentSerializer` in an inconsistent manner", "concise_description": "Class member `SearchResultSerializer.to_representation` overrides parent class `DocumentSerializer` in an inconsistent manner",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/documents.py",
"name": "bad-override-mutable-attribute", "name": "bad-override-mutable-attribute",
"concise_description": "Class member `Meta.list_serializer_class` overrides parent class `Meta` in an inconsistent manner", "concise_description": "Class member `Meta.list_serializer_class` overrides parent class `Meta` in an inconsistent manner",
"severity": "error" "severity": "error"
}, },
{
"column": 14,
"path": "src/documents/serialisers/metadata.py",
"name": "bad-assignment",
"concise_description": "`ManyRelatedField | RelatedField[@_, @_, Any]` is not assignable to attribute `parent` with type `BaseSerializer[Unknown]`",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/serialisers/metadata.py",
"name": "unsupported-operation",
"concise_description": "Cannot set item in `Mapping[str, Any]`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/serialisers/metadata.py",
"name": "bad-override-param-name",
"concise_description": "Class member `TagSerializer.validate` overrides parent class `MatchingModelSerializer` in an inconsistent manner",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/serialisers/metadata.py",
"name": "bad-argument-type",
"concise_description": "Argument `type[CustomField.FieldDataType]` is not assignable to parameter `choices` with type `Sequence[Any]` in function `rest_framework.fields.ChoiceField.__init__`",
"severity": "error"
},
{
"column": 13,
"path": "src/documents/serialisers/metadata.py",
"name": "bad-argument-type",
"concise_description": "Argument `str` is not assignable to parameter `data_type` with type `CustomField.FieldDataType` in function `documents.models.CustomFieldInstance.get_value_field_name`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/serialisers/metadata.py",
"name": "bad-override-param-name",
"concise_description": "Class member `CustomFieldInstanceSerializer.get_value` overrides parent class `ModelSerializer` in an inconsistent manner",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/serialisers/metadata.py",
"name": "bad-override-param-name",
"concise_description": "Class member `CustomFieldInstanceSerializer.validate` overrides parent class `ModelSerializer` in an inconsistent manner",
"severity": "error"
},
{
"column": 34,
"path": "src/documents/serialisers/metadata.py",
"name": "unsupported-operation",
"concise_description": "`None` is not subscriptable",
"severity": "error"
},
{ {
"column": 21, "column": 21,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/saved_views.py",
"name": "unsupported-operation", "name": "unsupported-operation",
"concise_description": "`Literal[SavedView.DisplayFields.CUSTOM_FIELD]` is not subscriptable", "concise_description": "`Literal[SavedView.DisplayFields.CUSTOM_FIELD]` is not subscriptable",
"severity": "error" "severity": "error"
}, },
{ {
"column": 36, "column": 36,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/saved_views.py",
"name": "unsupported-operation", "name": "unsupported-operation",
"concise_description": "`None` is not subscriptable", "concise_description": "`None` is not subscriptable",
"severity": "error" "severity": "error"
}, },
{
"column": 7,
"path": "src/documents/serialisers.py",
"name": "invalid-inheritance",
"concise_description": "Class `BulkEditSerializer` has inconsistent type arguments for base class `Field`: `Field[Any, Any, Any, dict[str, Any]]` and `Field[Any, Any, Any, dict[str, list[int]]]`",
"severity": "error"
},
{ {
"column": 73, "column": 73,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/sharing.py",
"name": "unbound-name", "name": "unbound-name",
"concise_description": "`address` is uninitialized", "concise_description": "`address` is uninitialized",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/system.py",
"name": "bad-override", "name": "bad-override",
"concise_description": "Class member `UiSettingsViewSerializer.create` overrides parent class `ModelSerializer` in an inconsistent manner", "concise_description": "Class member `UiSettingsViewSerializer.create` overrides parent class `ModelSerializer` in an inconsistent manner",
"severity": "error" "severity": "error"
}, },
{ {
"column": 46, "column": 46,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/tasks.py",
"name": "no-matching-overload", "name": "no-matching-overload",
"concise_description": "No matching overload found for function `dict.get` called with arguments: (str, str)", "concise_description": "No matching overload found for function `dict.get` called with arguments: (str, str)",
"severity": "error" "severity": "error"
}, },
{ {
"column": 38, "column": 38,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/tasks.py",
"name": "no-matching-overload", "name": "no-matching-overload",
"concise_description": "No matching overload found for function `dict.get` called with arguments: (str, str)", "concise_description": "No matching overload found for function `dict.get` called with arguments: (str, str)",
"severity": "error" "severity": "error"
}, },
{ {
"column": 51, "column": 51,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/tasks.py",
"name": "no-matching-overload", "name": "no-matching-overload",
"concise_description": "No matching overload found for function `dict.get` called with arguments: (str, Literal['manual_task'])", "concise_description": "No matching overload found for function `dict.get` called with arguments: (str, Literal['manual_task'])",
"severity": "error" "severity": "error"
}, },
{ {
"column": 52, "column": 52,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/workflows.py",
"name": "unbound-name", "name": "unbound-name",
"concise_description": "`triggers` may be uninitialized", "concise_description": "`triggers` may be uninitialized",
"severity": "error" "severity": "error"
}, },
{ {
"column": 62, "column": 62,
"path": "src/documents/serialisers.py", "path": "src/documents/serialisers/workflows.py",
"name": "unbound-name", "name": "unbound-name",
"concise_description": "`actions` may be uninitialized", "concise_description": "`actions` may be uninitialized",
"severity": "error" "severity": "error"
@@ -3619,389 +3612,389 @@
"concise_description": "`float | int | None` is not assignable to attribute `MAX_IMAGE_PIXELS` with type `int | None`", "concise_description": "`float | int | None` is not assignable to attribute `MAX_IMAGE_PIXELS` with type `int | None`",
"severity": "error" "severity": "error"
}, },
{
"column": 31,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `AbstractBaseUser` has no attribute `username`",
"severity": "error"
},
{
"column": 32,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of type `AbstractBaseUser | AnonymousUser` has no attribute `get_full_name`",
"severity": "error"
},
{ {
"column": 17, "column": 17,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `BulkPermissionMixin` has no attribute `queryset`", "concise_description": "Object of class `BulkPermissionMixin` has no attribute `queryset`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 19, "column": 19,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `object` has no attribute `get_serializer_context`", "concise_description": "Object of class `object` has no attribute `get_serializer_context`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 24, "column": 24,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `BulkPermissionMixin` has no attribute `filter_queryset`", "concise_description": "Object of class `BulkPermissionMixin` has no attribute `filter_queryset`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 45, "column": 45,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `BulkPermissionMixin` has no attribute `get_queryset`", "concise_description": "Object of class `BulkPermissionMixin` has no attribute `get_queryset`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 22, "column": 22,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `BulkPermissionMixin` has no attribute `queryset`", "concise_description": "Object of class `BulkPermissionMixin` has no attribute `queryset`",
"severity": "error" "severity": "error"
}, },
{
"column": 29,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `Self@CorrespondentViewSet` is not assignable to parameter `instance` with type `Options[Any] | None` in function `django.db.models.manager.BaseManager.__get__`",
"severity": "error"
},
{
"column": 29,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `annotate`",
"severity": "error"
},
{
"column": 25,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `Self@CorrespondentViewSet` is not assignable to parameter `instance` with type `Options[Any] | None` in function `django.db.models.manager.BaseManager.__get__`",
"severity": "error"
},
{
"column": 25,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `annotate`",
"severity": "error"
},
{
"column": 48,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `Correspondent` has no attribute `document_count`",
"severity": "error"
},
{
"column": 48,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `DocumentType` has no attribute `document_count`",
"severity": "error"
},
{
"column": 48,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `StoragePath` has no attribute `document_count`",
"severity": "error"
},
{
"column": 28,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Class `DocumentFilterSet` has no class attribute `declared_filters`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/views.py",
"name": "bad-override",
"concise_description": "Class member `DocumentViewSet.destroy` overrides parent class `DestroyModelMixin` in an inconsistent manner",
"severity": "error"
},
{
"column": 37,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `list[MetadataEntry] | list[Unknown] | None` is not assignable to parameter `original_metadata` with type `list[Unknown]` in function `documents.caching.set_metadata_cache`",
"severity": "error"
},
{
"column": 57,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_correspondents`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_tags`",
"severity": "error"
},
{
"column": 59,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_document_types`",
"severity": "error"
},
{
"column": 58,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_storage_paths`",
"severity": "error"
},
{ {
"column": 17, "column": 17,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "bad-argument-type",
"concise_description": "Argument `ClassificationSuggestions` is not assignable to parameter `suggestions` with type `dict[Unknown, Unknown]` in function `documents.caching.set_llm_suggestions_cache`",
"severity": "error"
},
{
"column": 5,
"path": "src/documents/views.py",
"name": "bad-specialization",
"concise_description": "`(self: Self@DocumentViewSet, request: Unknown, pk: Unknown | None = None) -> HttpResponseForbidden | Response | None` is not assignable to upper bound `(...) -> HttpResponseBase` of type variable `_View`",
"severity": "error"
},
{
"column": 36,
"path": "src/documents/views.py",
"name": "missing-argument",
"concise_description": "Missing argument `request` in function `DocumentViewSet.email_documents`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/views.py",
"name": "bad-override",
"concise_description": "Class member `UnifiedSearchViewSet.list` overrides parent class `DocumentViewSet` in an inconsistent manner",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of type `BasePagination | None` has no attribute `get_page_size`",
"severity": "error"
},
{
"column": 58,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of type `BasePagination | None` has no attribute `page_size`",
"severity": "error"
},
{
"column": 13,
"path": "src/documents/views.py",
"name": "not-iterable",
"concise_description": "Type `None` is not iterable",
"severity": "error"
},
{
"column": 43,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `TantivyRelevanceList` is not assignable to parameter `queryset` with type `QuerySet[Any, @_] | Sequence[@_]` in function `rest_framework.generics.GenericAPIView.paginate_queryset`",
"severity": "error"
},
{
"column": 25,
"path": "src/documents/views.py",
"name": "unsupported-operation",
"concise_description": "`+` is not supported between `None` and `Literal[1]`",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/views.py",
"name": "not-iterable", "name": "not-iterable",
"concise_description": "Type `None` is not iterable", "concise_description": "Type `None` is not iterable",
"severity": "error" "severity": "error"
}, },
{ {
"column": 18, "column": 18,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "bad-argument-type", "name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `DocumentSelectionMixin._resolve_document_ids`", "concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `DocumentSelectionMixin._resolve_document_ids`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 18, "column": 18,
"path": "src/documents/views.py", "path": "src/documents/views/base.py",
"name": "bad-argument-type", "name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `DocumentOperationPermissionMixin._has_document_permissions`", "concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `DocumentOperationPermissionMixin._has_document_permissions`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 18, "column": 18,
"path": "src/documents/views.py", "path": "src/documents/views/bulk_edit.py",
"name": "bad-argument-type", "name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `DocumentSelectionMixin._resolve_document_ids`", "concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `documents.views.base.DocumentSelectionMixin._resolve_document_ids`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 18, "column": 18,
"path": "src/documents/views.py", "path": "src/documents/views/bulk_edit.py",
"name": "bad-argument-type", "name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `DocumentOperationPermissionMixin._has_document_permissions`", "concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User` in function `documents.views.base.DocumentOperationPermissionMixin._has_document_permissions`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 33, "column": 33,
"path": "src/documents/views.py", "path": "src/documents/views/bulk_edit.py",
"name": "unbound-name", "name": "unbound-name",
"concise_description": "`old_values` may be uninitialized", "concise_description": "`old_values` may be uninitialized",
"severity": "error" "severity": "error"
}, },
{
"column": 52,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `Correspondent` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `Tag` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `DocumentType` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `StoragePath` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `CustomField` has no attribute `document_count`",
"severity": "error"
},
{
"column": 65,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser | None` is not assignable to parameter `user` with type `AbstractUser | None` in function `documents.search._backend.TantivyBackend.autocomplete`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/views.py",
"name": "bad-override",
"concise_description": "Class member `TasksViewSet.get_serializer_class` overrides parent class `ReadOnlyModelViewSet` in an inconsistent manner",
"severity": "error"
},
{
"column": 12,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `AbstractBaseUser` has no attribute `is_staff`",
"severity": "error"
},
{
"column": 44,
"path": "src/documents/views.py",
"name": "bad-argument-type",
"concise_description": "Argument `QuerySet[PaperlessTask, dict[str, Any]]` is not assignable to parameter `instance` with type `dict[str, Any] | None` in function `rest_framework.serializers.BaseSerializer.__init__`",
"severity": "error"
},
{
"column": 13,
"path": "src/documents/views.py",
"name": "missing-attribute",
"concise_description": "Object of class `Sequence` has no attribute `append`",
"severity": "error"
},
{ {
"column": 24, "column": 24,
"path": "src/documents/views.py", "path": "src/documents/views/bulk_edit.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `BaseSerializer` has no attribute `get_object_class`", "concise_description": "Object of class `BaseSerializer` has no attribute `get_object_class`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 45, "column": 45,
"path": "src/documents/views.py", "path": "src/documents/views/bulk_edit.py",
"name": "bad-argument-type", "name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User | None` in function `documents.permissions.permitted_object_ids`", "concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User | None` in function `documents.permissions.permitted_object_ids`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 16, "column": 16,
"path": "src/documents/views.py", "path": "src/documents/views/bulk_edit.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `AbstractBaseUser` has no attribute `is_superuser`", "concise_description": "Object of class `AbstractBaseUser` has no attribute `is_superuser`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 17, "column": 17,
"path": "src/documents/views.py", "path": "src/documents/views/bulk_edit.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `AbstractBaseUser` has no attribute `has_perm`", "concise_description": "Object of class `AbstractBaseUser` has no attribute `has_perm`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 48,
"path": "src/documents/views.py", "path": "src/documents/views/documents.py",
"name": "bad-override", "name": "missing-attribute",
"concise_description": "Class member `WorkflowTriggerViewSet.partial_update` overrides parent class `ModelViewSet` in an inconsistent manner", "concise_description": "Object of class `Correspondent` has no attribute `document_count`",
"severity": "error"
},
{
"column": 48,
"path": "src/documents/views/documents.py",
"name": "missing-attribute",
"concise_description": "Object of class `DocumentType` has no attribute `document_count`",
"severity": "error"
},
{
"column": 48,
"path": "src/documents/views/documents.py",
"name": "missing-attribute",
"concise_description": "Object of class `StoragePath` has no attribute `document_count`",
"severity": "error"
},
{
"column": 28,
"path": "src/documents/views/documents.py",
"name": "missing-attribute",
"concise_description": "Class `DocumentFilterSet` has no class attribute `declared_filters`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 9, "column": 9,
"path": "src/documents/views.py", "path": "src/documents/views/documents.py",
"name": "bad-override", "name": "bad-override",
"concise_description": "Class member `WorkflowActionViewSet.partial_update` overrides parent class `ModelViewSet` in an inconsistent manner", "concise_description": "Class member `DocumentViewSet.destroy` overrides parent class `DestroyModelMixin` in an inconsistent manner",
"severity": "error"
},
{
"column": 37,
"path": "src/documents/views/documents.py",
"name": "bad-argument-type",
"concise_description": "Argument `list[MetadataEntry] | list[Unknown] | None` is not assignable to parameter `original_metadata` with type `list[Unknown]` in function `documents.caching.set_metadata_cache`",
"severity": "error"
},
{
"column": 57,
"path": "src/documents/views/documents.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_correspondents`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views/documents.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_tags`",
"severity": "error"
},
{
"column": 59,
"path": "src/documents/views/documents.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_document_types`",
"severity": "error"
},
{
"column": 58,
"path": "src/documents/views/documents.py",
"name": "bad-argument-type",
"concise_description": "Argument `DocumentClassifier | None` is not assignable to parameter `classifier` with type `DocumentClassifier` in function `documents.matching.match_storage_paths`",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/views/documents.py",
"name": "bad-argument-type",
"concise_description": "Argument `ClassificationSuggestions` is not assignable to parameter `suggestions` with type `dict[Unknown, Unknown]` in function `documents.caching.set_llm_suggestions_cache`",
"severity": "error"
},
{
"column": 5,
"path": "src/documents/views/documents.py",
"name": "bad-specialization",
"concise_description": "`(self: Self@DocumentViewSet, request: Unknown, pk: Unknown | None = None) -> HttpResponseForbidden | Response | None` is not assignable to upper bound `(...) -> HttpResponseBase` of type variable `_View`",
"severity": "error"
},
{
"column": 36,
"path": "src/documents/views/documents.py",
"name": "missing-argument",
"concise_description": "Missing argument `request` in function `DocumentViewSet.email_documents`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/views/documents.py",
"name": "bad-override",
"concise_description": "Class member `UnifiedSearchViewSet.list` overrides parent class `DocumentViewSet` in an inconsistent manner",
"severity": "error"
},
{
"column": 17,
"path": "src/documents/views/documents.py",
"name": "missing-attribute",
"concise_description": "Object of type `BasePagination | None` has no attribute `get_page_size`",
"severity": "error"
},
{
"column": 58,
"path": "src/documents/views/documents.py",
"name": "missing-attribute",
"concise_description": "Object of type `BasePagination | None` has no attribute `page_size`",
"severity": "error"
},
{
"column": 13,
"path": "src/documents/views/documents.py",
"name": "not-iterable",
"concise_description": "Type `None` is not iterable",
"severity": "error"
},
{
"column": 43,
"path": "src/documents/views/documents.py",
"name": "bad-argument-type",
"concise_description": "Argument `TantivyRelevanceList` is not assignable to parameter `queryset` with type `QuerySet[Any, @_] | Sequence[@_]` in function `rest_framework.generics.GenericAPIView.paginate_queryset`",
"severity": "error"
},
{
"column": 25,
"path": "src/documents/views/documents.py",
"name": "unsupported-operation",
"concise_description": "`+` is not supported between `None` and `Literal[1]`",
"severity": "error"
},
{
"column": 31,
"path": "src/documents/views/index.py",
"name": "missing-attribute",
"concise_description": "Object of class `AbstractBaseUser` has no attribute `username`",
"severity": "error"
},
{
"column": 32,
"path": "src/documents/views/index.py",
"name": "missing-attribute",
"concise_description": "Object of type `AbstractBaseUser | AnonymousUser` has no attribute `get_full_name`",
"severity": "error"
},
{
"column": 16,
"path": "src/documents/views/index.py",
"name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `app_logo`",
"severity": "error"
},
{
"column": 29,
"path": "src/documents/views/metadata.py",
"name": "bad-argument-type",
"concise_description": "Argument `Self@CorrespondentViewSet` is not assignable to parameter `instance` with type `Options[Any] | None` in function `django.db.models.manager.BaseManager.__get__`",
"severity": "error"
},
{
"column": 29,
"path": "src/documents/views/metadata.py",
"name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `annotate`",
"severity": "error"
},
{
"column": 25,
"path": "src/documents/views/metadata.py",
"name": "bad-argument-type",
"concise_description": "Argument `Self@CorrespondentViewSet` is not assignable to parameter `instance` with type `Options[Any] | None` in function `django.db.models.manager.BaseManager.__get__`",
"severity": "error"
},
{
"column": 25,
"path": "src/documents/views/metadata.py",
"name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `annotate`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views/search.py",
"name": "missing-attribute",
"concise_description": "Object of class `Correspondent` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views/search.py",
"name": "missing-attribute",
"concise_description": "Object of class `Tag` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views/search.py",
"name": "missing-attribute",
"concise_description": "Object of class `DocumentType` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views/search.py",
"name": "missing-attribute",
"concise_description": "Object of class `StoragePath` has no attribute `document_count`",
"severity": "error"
},
{
"column": 52,
"path": "src/documents/views/search.py",
"name": "missing-attribute",
"concise_description": "Object of class `CustomField` has no attribute `document_count`",
"severity": "error"
},
{
"column": 65,
"path": "src/documents/views/search.py",
"name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser | None` is not assignable to parameter `user` with type `AbstractUser | None` in function `documents.search._backend.TantivyBackend.autocomplete`",
"severity": "error"
},
{
"column": 13,
"path": "src/documents/views/sharing.py",
"name": "missing-attribute",
"concise_description": "Object of class `Sequence` has no attribute `append`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 40, "column": 40,
"path": "src/documents/views.py", "path": "src/documents/views/system.py",
"name": "unbound-name", "name": "unbound-name",
"concise_description": "`all_migrations` may be uninitialized", "concise_description": "`all_migrations` may be uninitialized",
"severity": "error" "severity": "error"
}, },
{ {
"column": 17, "column": 17,
"path": "src/documents/views.py", "path": "src/documents/views/system.py",
"name": "bad-argument-type", "name": "bad-argument-type",
"concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User | None` in function `documents.permissions.permitted_document_ids`", "concise_description": "Argument `AbstractBaseUser | AnonymousUser` is not assignable to parameter `user` with type `User | None` in function `documents.permissions.permitted_document_ids`",
"severity": "error" "severity": "error"
}, },
{ {
"column": 16, "column": 9,
"path": "src/documents/views.py", "path": "src/documents/views/tasks.py",
"name": "bad-override",
"concise_description": "Class member `TasksViewSet.get_serializer_class` overrides parent class `ReadOnlyModelViewSet` in an inconsistent manner",
"severity": "error"
},
{
"column": 12,
"path": "src/documents/views/tasks.py",
"name": "missing-attribute", "name": "missing-attribute",
"concise_description": "Object of class `NoneType` has no attribute `app_logo`", "concise_description": "Object of class `AbstractBaseUser` has no attribute `is_staff`",
"severity": "error"
},
{
"column": 44,
"path": "src/documents/views/tasks.py",
"name": "bad-argument-type",
"concise_description": "Argument `QuerySet[PaperlessTask, dict[str, Any]]` is not assignable to parameter `instance` with type `dict[str, Any] | None` in function `rest_framework.serializers.BaseSerializer.__init__`",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/views/workflows.py",
"name": "bad-override",
"concise_description": "Class member `WorkflowTriggerViewSet.partial_update` overrides parent class `ModelViewSet` in an inconsistent manner",
"severity": "error"
},
{
"column": 9,
"path": "src/documents/views/workflows.py",
"name": "bad-override",
"concise_description": "Class member `WorkflowActionViewSet.partial_update` overrides parent class `ModelViewSet` in an inconsistent manner",
"severity": "error" "severity": "error"
}, },
{ {
+13 -4
View File
@@ -43,17 +43,26 @@ Once you have submitted a **P**ull **R**equest it will be reviewed, approved, an
Important: Pull requests that implement a new feature or enhancement _should almost always target an existing feature request_ with evidence of community interest and discussion. This is in order to balance the work of implementing and maintaining new features / enhancements. Instead of opening a PR which does not meet this requirement, please open a feature request instead, to gather feedback from both users and the project maintainers. Important: Pull requests that implement a new feature or enhancement _should almost always target an existing feature request_ with evidence of community interest and discussion. This is in order to balance the work of implementing and maintaining new features / enhancements. Instead of opening a PR which does not meet this requirement, please open a feature request instead, to gather feedback from both users and the project maintainers.
## PR Review Process ## Non-Trivial Requests
Our community review process for PRs is the following: PRs deemed `non-trivial` will go through a stricter review process before being merged into `dev`. This is to ensure code quality and complete functionality (free of side effects).
Examples of `non-trivial` PRs might include:
- Additional features
- Large changes to many distinct files
- Breaking or deprecation of existing features
Our community review process for `non-trivial` PRs is the following:
1. Must pass usual automated code tests and formatting checks. 1. Must pass usual automated code tests and formatting checks.
2. The PR will be assigned and pinged to the appropriately experienced team (i.e. @paperless-ngx/backend for backend changes). 2. The PR will be assigned and pinged to the appropriately experienced team (i.e. @paperless-ngx/backend for backend changes).
3. Development team will check and test code manually (possibly over several days). 3. Development team will check and test code manually (possibly over several days).
- You may be asked to make changes or rebase. - You may be asked to make changes or rebase.
4. One or more members of the team will approve and finally merge the request into `dev` 🎉. - The team may ask for additional testing done by @paperless-ngx/test
4. **At least two** members of the team will approve and finally merge the request into `dev` 🎉.
This process might be slow as community members have different schedules and time to dedicate to the Paperless project. However it ensures community code reviews are thorough and of high quality. This process might be slow as community members have different schedules and time to dedicate to the Paperless project. However it ensures community code reviews are as brilliantly thorough as they once were with @jonaswinkler.
# Use of AI Tools # Use of AI Tools
+8 -4
View File
@@ -21,7 +21,7 @@ Paperless-ngx is a document management system that transforms your physical docu
Paperless-ngx is the official successor to the original [Paperless](https://github.com/the-paperless-project/paperless) & [Paperless-ng](https://github.com/jonaswinkler/paperless-ng) projects and is designed to distribute the responsibility of advancing and supporting the project among a team of people. [Consider joining us!](#community-support) Paperless-ngx is the official successor to the original [Paperless](https://github.com/the-paperless-project/paperless) & [Paperless-ng](https://github.com/jonaswinkler/paperless-ng) projects and is designed to distribute the responsibility of advancing and supporting the project among a team of people. [Consider joining us!](#community-support)
Thanks to the generous folks at [Fyra Stack](https://fyrastack.com), a demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com) using login `demo` / `demo`. _Note: demo content is reset frequently and confidential information should not be uploaded._ Thanks to the generous folks at [DigitalOcean](https://m.do.co/c/8d70b916d462), a demo is available at [demo.paperless-ngx.com](https://demo.paperless-ngx.com) using login `demo` / `demo`. _Note: demo content is reset frequently and confidential information should not be uploaded._
- [Features](#features) - [Features](#features)
- [Getting started](#getting-started) - [Getting started](#getting-started)
@@ -33,9 +33,13 @@ Thanks to the generous folks at [Fyra Stack](https://fyrastack.com), a demo is a
- [Related Projects](#related-projects) - [Related Projects](#related-projects)
- [Important Note](#important-note) - [Important Note](#important-note)
<p align="right">Demo hosting provided by:<br/> <p align="right">This project is supported by:<br/>
<a href="https://fyrastack.com"> <a href="https://m.do.co/c/8d70b916d462" style="padding-top: 4px; display: block;">
<img src="docs/assets/sponsors/fyra-stack.svg" alt="" width="28px" align="absmiddle"> Fyra Stack <picture>
<source media="(prefers-color-scheme: dark)" srcset="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_white.svg" width="140px">
<source media="(prefers-color-scheme: light)" srcset="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="140px">
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_black_.svg" width="140px">
</picture>
</a> </a>
</p> </p>
+1 -1
View File
@@ -14,7 +14,7 @@ services:
command: command:
- "gotenberg" - "gotenberg"
- "--chromium-disable-javascript=true" - "--chromium-disable-javascript=true"
- "--chromium-allow-list=^file:///tmp/.*" - "--chromium-allow-list=file:///tmp/.*"
- "--log-level=warn" - "--log-level=warn"
- "--log-format=text" - "--log-format=text"
tika: tika:
@@ -40,6 +40,7 @@ services:
volumes: volumes:
- dbdata:/var/lib/mysql - dbdata:/var/lib/mysql
environment: environment:
MARIADB_HOST: paperless
MARIADB_DATABASE: paperless MARIADB_DATABASE: paperless
MARIADB_USER: paperless MARIADB_USER: paperless
MARIADB_PASSWORD: paperless MARIADB_PASSWORD: paperless
@@ -78,7 +79,7 @@ services:
command: command:
- "gotenberg" - "gotenberg"
- "--chromium-disable-javascript=true" - "--chromium-disable-javascript=true"
- "--chromium-allow-list=^file:///tmp/.*" - "--chromium-allow-list=file:///tmp/.*"
tika: tika:
image: docker.io/apache/tika:3.3.1.0 image: docker.io/apache/tika:3.3.1.0
restart: unless-stopped restart: unless-stopped
@@ -36,6 +36,7 @@ services:
volumes: volumes:
- dbdata:/var/lib/mysql - dbdata:/var/lib/mysql
environment: environment:
MARIADB_HOST: paperless
MARIADB_DATABASE: paperless MARIADB_DATABASE: paperless
MARIADB_USER: paperless MARIADB_USER: paperless
MARIADB_PASSWORD: paperless MARIADB_PASSWORD: paperless
@@ -74,7 +74,7 @@ services:
command: command:
- "gotenberg" - "gotenberg"
- "--chromium-disable-javascript=true" - "--chromium-disable-javascript=true"
- "--chromium-allow-list=^file:///tmp/.*" - "--chromium-allow-list=file:///tmp/.*"
tika: tika:
image: docker.io/apache/tika:3.3.1.0 image: docker.io/apache/tika:3.3.1.0
restart: unless-stopped restart: unless-stopped
@@ -63,7 +63,7 @@ services:
command: command:
- "gotenberg" - "gotenberg"
- "--chromium-disable-javascript=true" - "--chromium-disable-javascript=true"
- "--chromium-allow-list=^file:///tmp/.*" - "--chromium-allow-list=file:///tmp/.*"
tika: tika:
image: docker.io/apache/tika:3.3.1.0 image: docker.io/apache/tika:3.3.1.0
restart: unless-stopped restart: unless-stopped
-13
View File
@@ -1010,19 +1010,6 @@ documents to both separate and categorize them in a single operation.
**Example:** A 6-page scan with TAG:invoice on page 3 and TAG:receipt on page 5 will create **Example:** A 6-page scan with TAG:invoice on page 3 and TAG:receipt on page 5 will create
three documents: pages 1-2 (no tags), pages 3-4 (tagged "invoice"), and pages 5-6 (tagged "receipt"). three documents: pages 1-2 (no tags), pages 3-4 (tagged "invoice"), and pages 5-6 (tagged "receipt").
### Barcode Contents {#barcode-contents}
By default, Paperless only uses barcodes for splitting, ASNs and tags. With
[`PAPERLESS_CONSUMER_STORE_BARCODE_VALUES`](configuration.md#PAPERLESS_CONSUMER_STORE_BARCODE_VALUES)
enabled, it stores the content of every barcode with the document, e.g. payment codes or QR codes.
- Barcodes are listed on the **Metadata** tab with page, type and content, and can be copied.
- The API returns them in the `barcodes` field of `/api/documents/{id}/metadata/`.
- They can be [searched](usage.md#searching-barcodes), e.g. `barcodes:DE89370400440532013000`.
- Only the first [`PAPERLESS_CONSUMER_BARCODE_MAX_PAGES`](configuration.md#PAPERLESS_CONSUMER_BARCODE_MAX_PAGES)
pages are scanned. Reprocessing reads the barcodes of existing documents.
- Each version keeps its own barcodes, and the newest version's are shown and searched.
## Automatic collation of double-sided documents {#collate} ## Automatic collation of double-sided documents {#collate}
!!! note !!! note
-29
View File
@@ -101,32 +101,3 @@ h4 code {
border-top: .05rem solid var(--md-default-fg-color--lightest); border-top: .05rem solid var(--md-default-fg-color--lightest);
} }
} }
.md-typeset .demo-sponsor {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: .35rem;
margin-top: -1rem;
margin-bottom: 2rem;
color: var(--md-default-fg-color--light);
font-size: .65rem;
}
.md-typeset .demo-sponsor a {
display: inline-flex;
align-items: center;
gap: .25rem;
color: inherit;
font-weight: 600;
}
.md-typeset .demo-sponsor a:hover {
color: var(--md-accent-fg-color);
}
.md-typeset .demo-sponsor img {
width: 1rem;
height: 1rem;
flex-shrink: 0;
}
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="666.667" height="666.667" viewBox="0 0 666.667 666.667"><g stroke-width="1.333"><path fill="#fef400" d="m332.66668 418.66668h-84.66667v-85.33334-85.33333h84.66667 84.66667v-85.33334-85.333334h85.33333 85.33334v85.333334 85.33334h-85.33334-85.33333v85.33333 85.33334z"/><path fill="#fe6565" d="m248.00001 589.33335h-170.666674v-170.66667-170.66667h85.333334 85.33334v-85.33334-85.333334h84.66667 84.66667v85.333334 85.33334h85.33333 85.33334v85.33333 85.33334h-84.66667-84.66667v85.33334 85.33333zm84.66667-170.66667h84.66667v-85.33334-85.33333h-84.66667-84.66667v85.33333 85.33334z"/></g></svg>

Before

Width:  |  Height:  |  Size: 641 B

-174
View File
@@ -1,179 +1,5 @@
# Changelog # Changelog
## paperless-ngx 3.3.1
### Bug Fixes
- Fix: use a root document's effective content for the LLM index and pr… [@stumpylog](https://github.com/stumpylog) ([#14423](https://github.com/paperless-ngx/paperless-ngx/pull/14423))
- Fix: index document versions as their root document [@stumpylog](https://github.com/stumpylog) ([#14422](https://github.com/paperless-ngx/paperless-ngx/pull/14422))
- Fix: authorize document versions by their root in the single-object permission check [@stumpylog](https://github.com/stumpylog) ([#14421](https://github.com/paperless-ngx/paperless-ngx/pull/14421))
- Fix: Provide better error messages to users for invalid JSON [@stumpylog](https://github.com/stumpylog) ([#14419](https://github.com/paperless-ngx/paperless-ngx/pull/14419))
- Fix: authorize document versions by their root and speed up permission id sets [@stumpylog](https://github.com/stumpylog) ([#14396](https://github.com/paperless-ngx/paperless-ngx/pull/14396))
- Chore: update the db options warning [@shamoon](https://github.com/shamoon) ([#14398](https://github.com/paperless-ngx/paperless-ngx/pull/14398))
- Fix: bulk reprocess latest version for root documents [@shamoon](https://github.com/shamoon) ([#14385](https://github.com/paperless-ngx/paperless-ngx/pull/14385))
- Fix: consistently use root doc for version action permissions [@shamoon](https://github.com/shamoon) ([#14384](https://github.com/paperless-ngx/paperless-ngx/pull/14384))
- Fix: Don't attempt to index created dates which are not representable in the FTS index [@stumpylog](https://github.com/stumpylog) ([#14390](https://github.com/paperless-ngx/paperless-ngx/pull/14390))
- Fix: retry a search index rebuild that was interrupted [@stumpylog](https://github.com/stumpylog) ([#14379](https://github.com/paperless-ngx/paperless-ngx/pull/14379))
### Documentation
- Chore: silence gotenberg startup warning [@slankes](https://github.com/slankes) ([#14405](https://github.com/paperless-ngx/paperless-ngx/pull/14405))
- Documentation: remove MARIADB\_HOST from MariaDB compose files [@shamoon](https://github.com/shamoon) ([#14378](https://github.com/paperless-ngx/paperless-ngx/pull/14378))
- Documentation: Updates the troubleshooting with 2 common database collation issues [@stumpylog](https://github.com/stumpylog) ([#14370](https://github.com/paperless-ngx/paperless-ngx/pull/14370))
### Maintenance
- Chore: Upgrade runners to Ubuntu 26.04 [@stumpylog](https://github.com/stumpylog) ([#14347](https://github.com/paperless-ngx/paperless-ngx/pull/14347))
### Dependencies
- Chore(deps): Bump the npm\_and\_yarn group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14417](https://github.com/paperless-ngx/paperless-ngx/pull/14417))
### All App Changes
<details>
<summary>12 changes</summary>
- Chore: share the authorizing owner rule between the id sets and the trash filter [@stumpylog](https://github.com/stumpylog) ([#14425](https://github.com/paperless-ngx/paperless-ngx/pull/14425))
- Fix: use a root document's effective content for the LLM index and pr… [@stumpylog](https://github.com/stumpylog) ([#14423](https://github.com/paperless-ngx/paperless-ngx/pull/14423))
- Fix: index document versions as their root document [@stumpylog](https://github.com/stumpylog) ([#14422](https://github.com/paperless-ngx/paperless-ngx/pull/14422))
- Fix: authorize document versions by their root in the single-object permission check [@stumpylog](https://github.com/stumpylog) ([#14421](https://github.com/paperless-ngx/paperless-ngx/pull/14421))
- Fix: Provide better error messages to users for invalid JSON [@stumpylog](https://github.com/stumpylog) ([#14419](https://github.com/paperless-ngx/paperless-ngx/pull/14419))
- Chore(deps): Bump the npm\_and\_yarn group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14417](https://github.com/paperless-ngx/paperless-ngx/pull/14417))
- Fix: authorize document versions by their root and speed up permission id sets [@stumpylog](https://github.com/stumpylog) ([#14396](https://github.com/paperless-ngx/paperless-ngx/pull/14396))
- Chore: update the db options warning [@shamoon](https://github.com/shamoon) ([#14398](https://github.com/paperless-ngx/paperless-ngx/pull/14398))
- Fix: bulk reprocess latest version for root documents [@shamoon](https://github.com/shamoon) ([#14385](https://github.com/paperless-ngx/paperless-ngx/pull/14385))
- Fix: consistently use root doc for version action permissions [@shamoon](https://github.com/shamoon) ([#14384](https://github.com/paperless-ngx/paperless-ngx/pull/14384))
- Fix: Don't attempt to index created dates which are not representable in the FTS index [@stumpylog](https://github.com/stumpylog) ([#14390](https://github.com/paperless-ngx/paperless-ngx/pull/14390))
- Fix: retry a search index rebuild that was interrupted [@stumpylog](https://github.com/stumpylog) ([#14379](https://github.com/paperless-ngx/paperless-ngx/pull/14379))
</details>
## paperless-ngx 3.3.0
### Features / Enhancements
- Enhancement: more control over suggestion requests [@shamoon](https://github.com/shamoon) ([#14258](https://github.com/paperless-ngx/paperless-ngx/pull/14258))
- Chorehancement: set manifest CORS for credentials [@shamoon](https://github.com/shamoon) ([#14307](https://github.com/paperless-ngx/paperless-ngx/pull/14307))
- Enhancement: include Django admin with 2FA [@shamoon](https://github.com/shamoon) ([#14270](https://github.com/paperless-ngx/paperless-ngx/pull/14270))
- Feature: propagate resolved secrets to interactive container shells [@stumpylog](https://github.com/stumpylog) ([#14254](https://github.com/paperless-ngx/paperless-ngx/pull/14254))
- Enhancement: support separate embedding API key [@furkanural](https://github.com/furkanural) ([#14067](https://github.com/paperless-ngx/paperless-ngx/pull/14067))
- Enhancement: support passthrough extra params for LLMs [@shamoon](https://github.com/shamoon) ([#14202](https://github.com/paperless-ngx/paperless-ngx/pull/14202))
- Feature: store barcode contents, list and search them [@jurassicparkicecream](https://github.com/jurassicparkicecream) ([#14276](https://github.com/paperless-ngx/paperless-ngx/pull/14276))
### Bug Fixes
- Fix: Set the ProcessedMail owner based on the rule owner in all cases [@stumpylog](https://github.com/stumpylog) ([#14356](https://github.com/paperless-ngx/paperless-ngx/pull/14356))
- Fix: Ensure log rotation settings are converted to integers [@stumpylog](https://github.com/stumpylog) ([#14343](https://github.com/paperless-ngx/paperless-ngx/pull/14343))
- Fix: Wrap apt calls into a retry so we can ideally jump a slow mirror [@stumpylog](https://github.com/stumpylog) ([#14344](https://github.com/paperless-ngx/paperless-ngx/pull/14344))
- Fix: ship pdf.js CMaps so CJK documents render in the viewer [@MrOggy85](https://github.com/MrOggy85) ([#14318](https://github.com/paperless-ngx/paperless-ngx/pull/14318))
- Fix: use version page\_count for versioned document [@shamoon](https://github.com/shamoon) ([#14280](https://github.com/paperless-ngx/paperless-ngx/pull/14280))
- Fix: allow pointer events for pdf links in pngx viewer [@shamoon](https://github.com/shamoon) ([#14264](https://github.com/paperless-ngx/paperless-ngx/pull/14264))
- Fix: During a move to the trash directory, only attempt to copy metadata [@stumpylog](https://github.com/stumpylog) ([#14250](https://github.com/paperless-ngx/paperless-ngx/pull/14250))
- Fix: convert file mtime to the configured time zone directly [@stumpylog](https://github.com/stumpylog) ([#14249](https://github.com/paperless-ngx/paperless-ngx/pull/14249))
- Fix: ensure documentDeleted subscription is discarded [@shamoon](https://github.com/shamoon) ([#14247](https://github.com/paperless-ngx/paperless-ngx/pull/14247))
- Chore: Fix bugs in the test suite [@stumpylog](https://github.com/stumpylog) ([#14244](https://github.com/paperless-ngx/paperless-ngx/pull/14244))
- Fix: ensure bulk operations are checked against version root [@shamoon](https://github.com/shamoon) ([#14246](https://github.com/paperless-ngx/paperless-ngx/pull/14246))
- Fix: indexing after document-added workflows signal [@shamoon](https://github.com/shamoon) ([#14242](https://github.com/paperless-ngx/paperless-ngx/pull/14242))
- Fix: Record full tag and custom field lists in bulk edit audit log [@stumpylog](https://github.com/stumpylog) ([#14236](https://github.com/paperless-ngx/paperless-ngx/pull/14236))
- Chore: update pikepdf for ocrmypdf requirement [@shamoon](https://github.com/shamoon) ([#14235](https://github.com/paperless-ngx/paperless-ngx/pull/14235))
- Fix: handle legacy bulk edit split page range with missing page\_count [@shamoon](https://github.com/shamoon) ([#14212](https://github.com/paperless-ngx/paperless-ngx/pull/14212))
- Fix: ignore invalid EXIF orientation when generating image archives [@zhzy0077](https://github.com/zhzy0077) ([#14203](https://github.com/paperless-ngx/paperless-ngx/pull/14203))
### Documentation
- Documentation: correct duplicates info [@shamoon](https://github.com/shamoon) ([#14243](https://github.com/paperless-ngx/paperless-ngx/pull/14243))
### Maintenance
- Chore(deps): Bump the actions group across 1 directory with 4 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14332](https://github.com/paperless-ngx/paperless-ngx/pull/14332))
- Fix: Wrap apt calls into a retry so we can ideally jump a slow mirror [@stumpylog](https://github.com/stumpylog) ([#14344](https://github.com/paperless-ngx/paperless-ngx/pull/14344))
- Chore(deps): Bump the actions group across 1 directory with 10 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14301](https://github.com/paperless-ngx/paperless-ngx/pull/14301))
### Dependencies
<details>
<summary>27 changes</summary>
- Chore(deps): Bump django-filter from 25.2 to 26.1 @[dependabot[bot]](https://github.com/apps/dependabot) ([#14337](https://github.com/paperless-ngx/paperless-ngx/pull/14337))
- Chore(deps): Bump the utilities-patch group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14338](https://github.com/paperless-ngx/paperless-ngx/pull/14338))
- Chore(deps): Bump the pre-commit-dependencies group across 1 directory with 3 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14351](https://github.com/paperless-ngx/paperless-ngx/pull/14351))
- Chore(deps-dev): Bump types-channels from 4.3.0.20260408 to 4.3.0.20260518 @[dependabot[bot]](https://github.com/apps/dependabot) ([#14335](https://github.com/paperless-ngx/paperless-ngx/pull/14335))
- docker(deps): Bump astral-sh/uv from 0.12.20-python3.14-trixie-slim to 0.12.23-python3.14-trixie-slim @[dependabot[bot]](https://github.com/apps/dependabot) ([#14327](https://github.com/paperless-ngx/paperless-ngx/pull/14327))
- Chore(deps): Bump the actions group across 1 directory with 4 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14332](https://github.com/paperless-ngx/paperless-ngx/pull/14332))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14325](https://github.com/paperless-ngx/paperless-ngx/pull/14325))
- Chore(deps): Bump the frontend-angular-dependencies group across 1 directory with 13 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14329](https://github.com/paperless-ngx/paperless-ngx/pull/14329))
- Chore(deps-dev): Bump prettier from 3.9.8 to 3.9.9 in /src-ui @[dependabot[bot]](https://github.com/apps/dependabot) ([#14331](https://github.com/paperless-ngx/paperless-ngx/pull/14331))
- Chore(deps-dev): Bump the frontend-eslint-dependencies group across 1 directory with 3 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14330](https://github.com/paperless-ngx/paperless-ngx/pull/14330))
- Chore(deps-dev): Bump zensical from 0.0.64 to 0.0.65 in the development group @[dependabot[bot]](https://github.com/apps/dependabot) ([#14326](https://github.com/paperless-ngx/paperless-ngx/pull/14326))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14314](https://github.com/paperless-ngx/paperless-ngx/pull/14314))
- Chore(deps): Bump the utilities-minor group across 1 directory with 7 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14305](https://github.com/paperless-ngx/paperless-ngx/pull/14305))
- docker-compose(deps): bump greenmail/standalone from 2.1.13 to 2.1.14 in /docker/compose @[dependabot[bot]](https://github.com/apps/dependabot) ([#14281](https://github.com/paperless-ngx/paperless-ngx/pull/14281))
- docker(deps): Bump astral-sh/uv from 0.12.16-python3.14-trixie-slim to 0.12.20-python3.14-trixie-slim @[dependabot[bot]](https://github.com/apps/dependabot) ([#14282](https://github.com/paperless-ngx/paperless-ngx/pull/14282))
- Chore(deps): Bump the pre-commit-dependencies group across 1 directory with 3 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14283](https://github.com/paperless-ngx/paperless-ngx/pull/14283))
- Chore(deps): Bump the utilities-patch group across 1 directory with 6 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14297](https://github.com/paperless-ngx/paperless-ngx/pull/14297))
- Chore(deps): Bump the actions group across 1 directory with 10 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14301](https://github.com/paperless-ngx/paperless-ngx/pull/14301))
- Chore(deps-dev): Bump the frontend-jest-dependencies group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14286](https://github.com/paperless-ngx/paperless-ngx/pull/14286))
- Chore(deps-dev): Bump eslint from 10.10.0 to 10.11.0 in /src-ui in the frontend-eslint-dependencies group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#14287](https://github.com/paperless-ngx/paperless-ngx/pull/14287))
- Chore(deps-dev): Bump @types/node from 26.5.0 to 26.6.2 in /src-ui @[dependabot[bot]](https://github.com/apps/dependabot) ([#14288](https://github.com/paperless-ngx/paperless-ngx/pull/14288))
- Chore(deps-dev): Bump prettier from 3.9.6 to 3.9.8 in /src-ui @[dependabot[bot]](https://github.com/apps/dependabot) ([#14289](https://github.com/paperless-ngx/paperless-ngx/pull/14289))
- Chore(deps): Bump the frontend-angular-dependencies group across 1 directory with 10 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14285](https://github.com/paperless-ngx/paperless-ngx/pull/14285))
- Chore: replace bleach with turbohtml [@gaborbernat](https://github.com/gaborbernat) ([#14269](https://github.com/paperless-ngx/paperless-ngx/pull/14269))
- Chore(deps): Bump autobahn from 25.12.2 to 26.7.1 in the uv group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#14231](https://github.com/paperless-ngx/paperless-ngx/pull/14231))
- Chore: update pikepdf for ocrmypdf requirement [@shamoon](https://github.com/shamoon) ([#14235](https://github.com/paperless-ngx/paperless-ngx/pull/14235))
- Chore(deps): Bump the pre-commit-dependencies group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14133](https://github.com/paperless-ngx/paperless-ngx/pull/14133))
</details>
### All App Changes
<details>
<summary>41 changes</summary>
- Feature: store barcode contents, list and search them [@jurassicparkicecream](https://github.com/jurassicparkicecream) ([#14276](https://github.com/paperless-ngx/paperless-ngx/pull/14276))
- Fix: Set the ProcessedMail owner based on the rule owner in all cases [@stumpylog](https://github.com/stumpylog) ([#14356](https://github.com/paperless-ngx/paperless-ngx/pull/14356))
- Chore(deps): Bump django-filter from 25.2 to 26.1 @[dependabot[bot]](https://github.com/apps/dependabot) ([#14337](https://github.com/paperless-ngx/paperless-ngx/pull/14337))
- Chore(deps): Bump the utilities-patch group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14338](https://github.com/paperless-ngx/paperless-ngx/pull/14338))
- Chore(deps-dev): Bump types-channels from 4.3.0.20260408 to 4.3.0.20260518 @[dependabot[bot]](https://github.com/apps/dependabot) ([#14335](https://github.com/paperless-ngx/paperless-ngx/pull/14335))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14325](https://github.com/paperless-ngx/paperless-ngx/pull/14325))
- Fix: Ensure log rotation settings are converted to integers [@stumpylog](https://github.com/stumpylog) ([#14343](https://github.com/paperless-ngx/paperless-ngx/pull/14343))
- Chore(deps): Bump the frontend-angular-dependencies group across 1 directory with 13 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14329](https://github.com/paperless-ngx/paperless-ngx/pull/14329))
- Chore(deps-dev): Bump prettier from 3.9.8 to 3.9.9 in /src-ui @[dependabot[bot]](https://github.com/apps/dependabot) ([#14331](https://github.com/paperless-ngx/paperless-ngx/pull/14331))
- Chore(deps-dev): Bump the frontend-eslint-dependencies group across 1 directory with 3 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14330](https://github.com/paperless-ngx/paperless-ngx/pull/14330))
- Fix: ship pdf.js CMaps so CJK documents render in the viewer [@MrOggy85](https://github.com/MrOggy85) ([#14318](https://github.com/paperless-ngx/paperless-ngx/pull/14318))
- Chore(deps-dev): Bump zensical from 0.0.64 to 0.0.65 in the development group @[dependabot[bot]](https://github.com/apps/dependabot) ([#14326](https://github.com/paperless-ngx/paperless-ngx/pull/14326))
- Enhancement: more control over suggestion requests [@shamoon](https://github.com/shamoon) ([#14258](https://github.com/paperless-ngx/paperless-ngx/pull/14258))
- Chore(deps): Bump the uv group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14314](https://github.com/paperless-ngx/paperless-ngx/pull/14314))
- Chore: anchor admin url pattern [@shamoon](https://github.com/shamoon) ([#14316](https://github.com/paperless-ngx/paperless-ngx/pull/14316))
- Chorehancement: set manifest CORS for credentials [@shamoon](https://github.com/shamoon) ([#14307](https://github.com/paperless-ngx/paperless-ngx/pull/14307))
- Chore(deps): Bump the utilities-minor group across 1 directory with 7 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14305](https://github.com/paperless-ngx/paperless-ngx/pull/14305))
- Chore(deps): Bump the utilities-patch group across 1 directory with 6 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14297](https://github.com/paperless-ngx/paperless-ngx/pull/14297))
- Chore(deps-dev): Bump the frontend-jest-dependencies group across 1 directory with 2 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14286](https://github.com/paperless-ngx/paperless-ngx/pull/14286))
- Chore(deps-dev): Bump eslint from 10.10.0 to 10.11.0 in /src-ui in the frontend-eslint-dependencies group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#14287](https://github.com/paperless-ngx/paperless-ngx/pull/14287))
- Chore(deps-dev): Bump @types/node from 26.5.0 to 26.6.2 in /src-ui @[dependabot[bot]](https://github.com/apps/dependabot) ([#14288](https://github.com/paperless-ngx/paperless-ngx/pull/14288))
- Chore(deps-dev): Bump prettier from 3.9.6 to 3.9.8 in /src-ui @[dependabot[bot]](https://github.com/apps/dependabot) ([#14289](https://github.com/paperless-ngx/paperless-ngx/pull/14289))
- Chore(deps): Bump the frontend-angular-dependencies group across 1 directory with 10 updates @[dependabot[bot]](https://github.com/apps/dependabot) ([#14285](https://github.com/paperless-ngx/paperless-ngx/pull/14285))
- Fix: use version page\_count for versioned document [@shamoon](https://github.com/shamoon) ([#14280](https://github.com/paperless-ngx/paperless-ngx/pull/14280))
- Chore: replace bleach with turbohtml [@gaborbernat](https://github.com/gaborbernat) ([#14269](https://github.com/paperless-ngx/paperless-ngx/pull/14269))
- Enhancement: include Django admin with 2FA [@shamoon](https://github.com/shamoon) ([#14270](https://github.com/paperless-ngx/paperless-ngx/pull/14270))
- Fix: allow pointer events for pdf links in pngx viewer [@shamoon](https://github.com/shamoon) ([#14264](https://github.com/paperless-ngx/paperless-ngx/pull/14264))
- Feature: propagate resolved secrets to interactive container shells [@stumpylog](https://github.com/stumpylog) ([#14254](https://github.com/paperless-ngx/paperless-ngx/pull/14254))
- Fix: During a move to the trash directory, only attempt to copy metadata [@stumpylog](https://github.com/stumpylog) ([#14250](https://github.com/paperless-ngx/paperless-ngx/pull/14250))
- Fix: convert file mtime to the configured time zone directly [@stumpylog](https://github.com/stumpylog) ([#14249](https://github.com/paperless-ngx/paperless-ngx/pull/14249))
- Fix: ensure documentDeleted subscription is discarded [@shamoon](https://github.com/shamoon) ([#14247](https://github.com/paperless-ngx/paperless-ngx/pull/14247))
- Chore: Fix bugs in the test suite [@stumpylog](https://github.com/stumpylog) ([#14244](https://github.com/paperless-ngx/paperless-ngx/pull/14244))
- Fix: ensure bulk operations are checked against version root [@shamoon](https://github.com/shamoon) ([#14246](https://github.com/paperless-ngx/paperless-ngx/pull/14246))
- Enhancement: support separate embedding API key [@furkanural](https://github.com/furkanural) ([#14067](https://github.com/paperless-ngx/paperless-ngx/pull/14067))
- Enhancement: support passthrough extra params for LLMs [@shamoon](https://github.com/shamoon) ([#14202](https://github.com/paperless-ngx/paperless-ngx/pull/14202))
- Chore(deps): Bump autobahn from 25.12.2 to 26.7.1 in the uv group across 1 directory @[dependabot[bot]](https://github.com/apps/dependabot) ([#14231](https://github.com/paperless-ngx/paperless-ngx/pull/14231))
- Fix: indexing after document-added workflows signal [@shamoon](https://github.com/shamoon) ([#14242](https://github.com/paperless-ngx/paperless-ngx/pull/14242))
- Fix: Record full tag and custom field lists in bulk edit audit log [@stumpylog](https://github.com/stumpylog) ([#14236](https://github.com/paperless-ngx/paperless-ngx/pull/14236))
- Chore: update pikepdf for ocrmypdf requirement [@shamoon](https://github.com/shamoon) ([#14235](https://github.com/paperless-ngx/paperless-ngx/pull/14235))
- Fix: handle legacy bulk edit split page range with missing page\_count [@shamoon](https://github.com/shamoon) ([#14212](https://github.com/paperless-ngx/paperless-ngx/pull/14212))
- Fix: ignore invalid EXIF orientation when generating image archives [@zhzy0077](https://github.com/zhzy0077) ([#14203](https://github.com/paperless-ngx/paperless-ngx/pull/14203))
</details>
## paperless-ngx 3.2.1 ## paperless-ngx 3.2.1
### Bug Fixes ### Bug Fixes
-7
View File
@@ -1796,13 +1796,6 @@ assigns or creates tags if a properly formatted barcode is detected.
Defaults to false. Defaults to false.
#### [`PAPERLESS_CONSUMER_STORE_BARCODE_VALUES=<bool>`](#PAPERLESS_CONSUMER_STORE_BARCODE_VALUES) {#PAPERLESS_CONSUMER_STORE_BARCODE_VALUES}
: Stores the content of every barcode found during consumption, see
[Barcode Contents](advanced_usage.md#barcode-contents).
Defaults to false.
## Audit Trail ## Audit Trail
#### [`PAPERLESS_AUDIT_LOG_ENABLED=<bool>`](#PAPERLESS_AUDIT_LOG_ENABLED) {#PAPERLESS_AUDIT_LOG_ENABLED} #### [`PAPERLESS_AUDIT_LOG_ENABLED=<bool>`](#PAPERLESS_AUDIT_LOG_ENABLED) {#PAPERLESS_AUDIT_LOG_ENABLED}
+1 -3
View File
@@ -76,9 +76,7 @@ is not supported by any of the available parsers.
**A:** Not by default. As of v3, a file whose contents match an existing document is still **A:** Not by default. As of v3, a file whose contents match an existing document is still
consumed, and the duplicate is flagged in the UI — open the document and check the consumed, and the duplicate is flagged in the UI — open the document and check the
**Duplicates** tab to review documents that share the same content, or filter the document **Duplicates** tab to review documents that share the same content. If you prefer the old
list by **Duplicates** to find all of them (see
[Duplicate documents](usage.md#duplicate-documents)). If you prefer the old
behavior of rejecting duplicates during consumption, set behavior of rejecting duplicates during consumption, set
[`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES) [`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES)
to `true`. to `true`.
+4 -4
View File
@@ -12,10 +12,10 @@ physical documents into a searchable online archive so you can keep, well, _less
[Get started](setup.md){ .md-button .md-button--primary .index-callout } [Get started](setup.md){ .md-button .md-button--primary .index-callout }
[Demo](https://demo.paperless-ngx.com){ .md-button .md-button--secondary target=\_blank } [Demo](https://demo.paperless-ngx.com){ .md-button .md-button--secondary target=\_blank }
<div class="demo-sponsor"> <div style="display: flex; justify-content: end; margin-top: -1.5rem;">
<span>Demo hosting by</span> <a href="https://m.do.co/c/8d70b916d462" target="_blank">
<a href="https://fyrastack.com" target="_blank" rel="noopener"> <img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_white.svg#only-dark" class="no-lightbox" width="150px">
<img src="assets/sponsors/fyra-stack.svg" alt="" class="no-lightbox" width="20" height="20"> Fyra Stack <img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_black.svg#only-light" class="no-lightbox" width="150px">
</a> </a>
</div> </div>
+1 -60
View File
@@ -129,7 +129,7 @@ change in the `docker-compose.yml` file:
command: command:
- 'gotenberg' - 'gotenberg'
- '--chromium-disable-javascript=true' - '--chromium-disable-javascript=true'
- '--chromium-allow-list=^file:///tmp/.*' - '--chromium-allow-list=file:///tmp/.*'
- '--api-timeout=60s' - '--api-timeout=60s'
``` ```
@@ -272,65 +272,6 @@ This error can occur in installations which have upgraded from a version of Pape
$ python3 manage.py convert_mariadb_uuid $ python3 manage.py convert_mariadb_uuid
``` ```
## MariaDB/MySQL error "Illegal mix of collations"
Consumption or other operations fail with an error like:
```
(1267, "Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and
(utf8mb4_unicode_ci,IMPLICIT) for operation '='")
```
This happens when the tables in your database do not all use the same
collation. It is most often seen on databases that existed before a
MariaDB/MySQL upgrade: older tables keep their original collation, while
tables created afterwards use the new server default.
To work around it, set the collation your existing tables use (the one in the error
that is not `utf8mb4_unicode_ci`) with
[`PAPERLESS_DB_OPTIONS`](configuration.md#PAPERLESS_DB_OPTIONS):
```bash
PAPERLESS_DB_OPTIONS="collation=utf8mb4_general_ci"
```
To fix it permanently, back up your database, then convert the database and
each table to a single collation and remove the override:
```sql
ALTER DATABASE paperless CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
## PostgreSQL warns about a "collation version mismatch"
The PostgreSQL log shows a warning like:
```
WARNING: database "paperless" has a collation version mismatch
DETAIL: The database was created using collation version 2.36, but the operating system provides version 2.41.
HINT: Rebuild all objects in this database that use the default collation and run ALTER DATABASE paperless REFRESH COLLATION VERSION, or build PostgreSQL with the right library version.
```
This comes from PostgreSQL, not Paperless-ngx. The `glibc` version that PostgreSQL
runs against changed, and the existing database was created with an older one. With
Docker, `glibc` comes from the PostgreSQL image's Debian base, not the host, so this
commonly happens when a new image is pulled after its base Debian release changed.
If PostgreSQL is installed directly on a host, it uses the host's `glibc` instead.
The warning is not an error and Paperless-ngx keeps working, but the database's text
indexes may be built with outdated sorting rules. To resolve it, back up your
database, then connect to it (for example with `psql -U paperless -d paperless`
inside the database container) and run:
```sql
REINDEX DATABASE paperless;
ALTER DATABASE paperless REFRESH COLLATION VERSION;
```
To avoid this in the future, pin your PostgreSQL image to a specific Debian release,
for example `postgres:18-trixie`, rather than `postgres:18`.
## Platform-Specific Deployment Troubleshooting ## Platform-Specific Deployment Troubleshooting
A user-maintained wiki page is available to help troubleshoot issues that may arise when trying to deploy Paperless-ngx on specific platforms, for example SELinux. Please see [the wiki](https://github.com/paperless-ngx/paperless-ngx/wiki/Platform%E2%80%90Specific-Troubleshooting). A user-maintained wiki page is available to help troubleshoot issues that may arise when trying to deploy Paperless-ngx on specific platforms, for example SELinux. Please see [the wiki](https://github.com/paperless-ngx/paperless-ngx/wiki/Platform%E2%80%90Specific-Troubleshooting).
+8 -21
View File
@@ -299,18 +299,19 @@ for details.
### Duplicate documents ### Duplicate documents
By default, Paperless-ngx **does not reject duplicates**. If you consume a file whose By default, Paperless-ngx **does not reject duplicates**. If you consume a file whose
contents match an existing document (same original or archive checksum), the new copy is contents exactly match an existing document (same checksum), the new copy is still
still consumed and a warning is logged. consumed and a warning is logged. The task entry for the upload also flags that a
duplicate was detected and links to the existing document(s).
When a document has duplicates, a **Duplicates** tab appears on its detail page, listing To review duplicates, open a document and switch to the **Duplicates** tab on the
the other documents you can view that share the same content (including any in the trash). document detail page. It lists other documents that share the same content, including any
To find all documents with duplicates, choose **Duplicates** in the document list's text that are in the trash (shown with a badge), and links to each so you can decide which to
filter dropdown, or use `has_duplicates=true` in the REST API. keep.
If you would rather reject duplicates at consumption time (the pre-v3 behavior), set If you would rather reject duplicates at consumption time (the pre-v3 behavior), set
[`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES) [`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES)
to `true`. The duplicate file is then deleted instead of consumed, and the task fails with to `true`. The duplicate file is then deleted instead of consumed, and the task fails with
a "Document already exists" message linking to the existing document. a "document already exists" message.
## Document Suggestions ## Document Suggestions
@@ -1060,20 +1061,6 @@ notes.user:alice notes.note:insurance
The bare `notes:` prefix is shorthand for `notes.note:`. The bare `notes:` prefix is shorthand for `notes.note:`.
#### Searching barcodes
If [barcode contents are stored](advanced_usage.md#barcode-contents), they can be searched by
content or type, but only with a field name:
```
barcodes.value:DE89370400440532013000
barcodes.format:qrcode
barcodes:wifi barcodes:guest
```
`barcodes:` is shorthand for `barcodes.value:`. Separators are stripped, so each part of e.g.
`WIFI:S:Guest;P:secret;;` can be searched on its own.
All of these can be combined. Syntax not described here may not work as expected, and an unknown field name is searched as ordinary text. All of these can be combined. Syntax not described here may not work as expected, and an unknown field name is searched as ordinary text.
!!! note !!! note
+3 -3
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "paperless-ngx" name = "paperless-ngx"
version = "3.3.1" version = "3.2.1"
description = """\ description = """\
A community-supported supercharged document management system: scan, index and archive all your physical documents\ A community-supported supercharged document management system: scan, index and archive all your physical documents\
""" """
@@ -33,7 +33,7 @@ dependencies = [
"django-compression-middleware~=0.5.0", "django-compression-middleware~=0.5.0",
"django-cors-headers~=4.9.0", "django-cors-headers~=4.9.0",
"django-extensions~=4.1", "django-extensions~=4.1",
"django-filter>=25.1,<27", "django-filter~=25.1",
"django-guardian>=3.3.3,<3.6", "django-guardian>=3.3.3,<3.6",
"django-multiselectfield~=1.0.1", "django-multiselectfield~=1.0.1",
"django-rich~=2.2.0", "django-rich~=2.2.0",
@@ -90,7 +90,7 @@ postgres = [
"psycopg[c,pool]==3.3.4", "psycopg[c,pool]==3.3.4",
# Direct dependency for proper resolution of the pre-built wheels # Direct dependency for proper resolution of the pre-built wheels
"psycopg-c==3.3.4", "psycopg-c==3.3.4",
"psycopg-pool==3.3.3", "psycopg-pool==3.3.2",
] ]
webserver = [ webserver = [
"granian[uvloop]>=2.7,<2.9", "granian[uvloop]>=2.7,<2.9",
+1 -1
View File
@@ -2,5 +2,5 @@
docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:15 docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -v paperless_pgdata:/var/lib/postgresql/data -d postgres:15
docker run -d -p 6379:6379 redis:latest docker run -d -p 6379:6379 redis:latest
docker run -p 3000:3000 -d gotenberg/gotenberg:7.8 gotenberg --chromium-disable-javascript=true --chromium-allow-list="^file:///tmp/.*" docker run -p 3000:3000 -d gotenberg/gotenberg:7.8 gotenberg --chromium-disable-javascript=true --chromium-allow-list="file:///tmp/.*"
docker run -p 9998:9998 -d docker.io/apache/tika:latest docker run -p 9998:9998 -d docker.io/apache/tika:latest
+113 -150
View File
@@ -698,7 +698,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">463,464</context> <context context-type="linenumber">457,458</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.html</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/custom-fields-bulk-edit-dialog/custom-fields-bulk-edit-dialog.component.html</context>
@@ -870,7 +870,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">482</context> <context context-type="linenumber">476</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
@@ -1373,7 +1373,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1907</context> <context context-type="linenumber">1901</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1577733187050997705" datatype="html"> <trans-unit id="1577733187050997705" datatype="html">
@@ -1451,7 +1451,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">408,409</context> <context context-type="linenumber">402,403</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
@@ -1700,7 +1700,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">179</context> <context context-type="linenumber">177</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2691296884221415710" datatype="html"> <trans-unit id="2691296884221415710" datatype="html">
@@ -1715,7 +1715,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">184</context> <context context-type="linenumber">182</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
@@ -1750,7 +1750,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">188</context> <context context-type="linenumber">186</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
@@ -1785,7 +1785,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">192</context> <context context-type="linenumber">190</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.html</context>
@@ -2478,7 +2478,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">713</context> <context context-type="linenumber">711</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-version-dropdown/document-version-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-version-dropdown/document-version-dropdown.component.html</context>
@@ -3392,11 +3392,11 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1521</context> <context context-type="linenumber">1515</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1908</context> <context context-type="linenumber">1902</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -4012,7 +4012,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1474</context> <context context-type="linenumber">1468</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -4156,7 +4156,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1961</context> <context context-type="linenumber">1955</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6661109599266152398" datatype="html"> <trans-unit id="6661109599266152398" datatype="html">
@@ -4167,7 +4167,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1962</context> <context context-type="linenumber">1956</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5162686434580248853" datatype="html"> <trans-unit id="5162686434580248853" datatype="html">
@@ -4178,7 +4178,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1963</context> <context context-type="linenumber">1957</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6665634854532231106" datatype="html"> <trans-unit id="6665634854532231106" datatype="html">
@@ -5430,7 +5430,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">374,375</context> <context context-type="linenumber">368,369</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8057014866157903311" datatype="html"> <trans-unit id="8057014866157903311" datatype="html">
@@ -6311,7 +6311,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1478</context> <context context-type="linenumber">1472</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -6344,7 +6344,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">177</context> <context context-type="linenumber">175</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context> <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
@@ -7176,10 +7176,6 @@
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context> <context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
<context context-type="linenumber">56,57</context> <context context-type="linenumber">56,57</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-barcodes/document-barcodes.component.html</context>
<context context-type="linenumber">5,6</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="1230154438678955604" datatype="html"> <trans-unit id="1230154438678955604" datatype="html">
<source>Change</source> <source>Change</source>
@@ -7752,8 +7748,8 @@
<context context-type="linenumber">120</context> <context context-type="linenumber">120</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5377184518735933155" datatype="html"> <trans-unit id="5700628356844396417" datatype="html">
<source>{VAR_PLURAL, plural, =1 {1 suggestion available below} other {<x id="INTERPOLATION"/> suggestions available below}}</source> <source>{VAR_PLURAL, plural, =1 {1 existing value suggested below} other {<x id="INTERPOLATION"/> existing values suggested below}}</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/suggestions-dropdown/suggestions-dropdown.component.html</context> <context context-type="sourcefile">src/app/components/common/suggestions-dropdown/suggestions-dropdown.component.html</context>
<context context-type="linenumber">54</context> <context context-type="linenumber">54</context>
@@ -8337,10 +8333,6 @@
</trans-unit> </trans-unit>
<trans-unit id="1407560924967345762" datatype="html"> <trans-unit id="1407560924967345762" datatype="html">
<source>Page</source> <source>Page</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-barcodes/document-barcodes.component.html</context>
<context context-type="linenumber">4,5</context>
</context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">5,6</context> <context context-type="linenumber">5,6</context>
@@ -8354,28 +8346,6 @@
<context context-type="linenumber">34</context> <context context-type="linenumber">34</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6205355627445317276" datatype="html">
<source>Content</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-barcodes/document-barcodes.component.html</context>
<context context-type="linenumber">6,7</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">300,301</context>
</context-group>
</trans-unit>
<trans-unit id="3846359579066496296" datatype="html">
<source>Copy content</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-barcodes/document-barcodes.component.html</context>
<context context-type="linenumber">32,33</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-barcodes/document-barcodes.component.html</context>
<context context-type="linenumber">40,41</context>
</context-group>
</trans-unit>
<trans-unit id="2266163016683537825" datatype="html"> <trans-unit id="2266163016683537825" datatype="html">
<source>of <x id="INTERPOLATION" equiv-text="{{previewNumPages()}}"/></source> <source>of <x id="INTERPOLATION" equiv-text="{{previewNumPages()}}"/></source>
<context-group purpose="location"> <context-group purpose="location">
@@ -8507,32 +8477,39 @@
<source>Details</source> <source>Details</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">174,175</context> <context context-type="linenumber">172,173</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5114742157723900905" datatype="html"> <trans-unit id="5114742157723900905" datatype="html">
<source>Date created</source> <source>Date created</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">181</context> <context context-type="linenumber">179</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5607669932062416162" datatype="html"> <trans-unit id="5607669932062416162" datatype="html">
<source>Default</source> <source>Default</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">193</context> <context context-type="linenumber">191</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context> <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
<context context-type="linenumber">71</context> <context context-type="linenumber">71</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6205355627445317276" datatype="html">
<source>Content</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">298,299</context>
</context-group>
</trans-unit>
<trans-unit id="218403386307979629" datatype="html"> <trans-unit id="218403386307979629" datatype="html">
<source>Metadata</source> <source>Metadata</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">309,310</context> <context context-type="linenumber">307,308</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts</context>
@@ -8543,235 +8520,228 @@
<source>Date modified</source> <source>Date modified</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">316,317</context> <context context-type="linenumber">314,315</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6392918669949841614" datatype="html"> <trans-unit id="6392918669949841614" datatype="html">
<source>Date added</source> <source>Date added</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">320,321</context> <context context-type="linenumber">318,319</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="146828917013192897" datatype="html"> <trans-unit id="146828917013192897" datatype="html">
<source>Media filename</source> <source>Media filename</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">324,325</context> <context context-type="linenumber">322,323</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4500855521601039868" datatype="html"> <trans-unit id="4500855521601039868" datatype="html">
<source>Original filename</source> <source>Original filename</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">328,329</context> <context context-type="linenumber">326,327</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2659735245739197634" datatype="html"> <trans-unit id="2659735245739197634" datatype="html">
<source>Original SHA256 checksum</source> <source>Original SHA256 checksum</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">332,333</context> <context context-type="linenumber">330,331</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5888243105821763422" datatype="html"> <trans-unit id="5888243105821763422" datatype="html">
<source>Original file size</source> <source>Original file size</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">336,337</context> <context context-type="linenumber">334,335</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2696647325713149563" datatype="html"> <trans-unit id="2696647325713149563" datatype="html">
<source>Original mime type</source> <source>Original mime type</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">340,341</context> <context context-type="linenumber">338,339</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6714358112223607756" datatype="html"> <trans-unit id="6714358112223607756" datatype="html">
<source>Archive SHA256 checksum</source> <source>Archive SHA256 checksum</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">345,346</context> <context context-type="linenumber">343,344</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6033581412811562084" datatype="html"> <trans-unit id="6033581412811562084" datatype="html">
<source>Archive file size</source> <source>Archive file size</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">351,352</context> <context context-type="linenumber">349,350</context>
</context-group>
</trans-unit>
<trans-unit id="8459338343197260257" datatype="html">
<source>Barcodes</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">360,361</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6992781481378431874" datatype="html"> <trans-unit id="6992781481378431874" datatype="html">
<source>Original document metadata</source> <source>Original document metadata</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">364</context> <context context-type="linenumber">358</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2846565152091361585" datatype="html"> <trans-unit id="2846565152091361585" datatype="html">
<source>Archived document metadata</source> <source>Archived document metadata</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">367</context> <context context-type="linenumber">361</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7206723502037428235" datatype="html"> <trans-unit id="7206723502037428235" datatype="html">
<source>Notes <x id="START_BLOCK_IF" equiv-text="@if (document()?.notes.length) {"/><x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="{{document().notes.length}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/><x id="CLOSE_BLOCK_IF" equiv-text="}"/></source> <source>Notes <x id="START_BLOCK_IF" equiv-text="@if (document()?.notes.length) {"/><x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="{{document().notes.length}}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/><x id="CLOSE_BLOCK_IF" equiv-text="}"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">386,389</context> <context context-type="linenumber">380,383</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="186236568870281953" datatype="html"> <trans-unit id="186236568870281953" datatype="html">
<source>History</source> <source>History</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">397,398</context> <context context-type="linenumber">391,392</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8236092845697214347" datatype="html"> <trans-unit id="8236092845697214347" datatype="html">
<source> Duplicates <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="{{ document().duplicate_documents.length }}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/></source> <source> Duplicates <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;badge text-bg-secondary ms-1&quot;&gt;"/><x id="INTERPOLATION" equiv-text="{{ document().duplicate_documents.length }}"/><x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span&gt;"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">420,423</context> <context context-type="linenumber">414,417</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6449374629822973702" datatype="html"> <trans-unit id="6449374629822973702" datatype="html">
<source>Duplicate documents detected:</source> <source>Duplicate documents detected:</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">425,426</context> <context context-type="linenumber">419,420</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="14058600336670816" datatype="html"> <trans-unit id="14058600336670816" datatype="html">
<source>In trash</source> <source>In trash</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">436,437</context> <context context-type="linenumber">430,431</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5129524307369213584" datatype="html"> <trans-unit id="5129524307369213584" datatype="html">
<source>Save &amp; next</source> <source>Save &amp; next</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">465</context> <context context-type="linenumber">459</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4910102545766233758" datatype="html"> <trans-unit id="4910102545766233758" datatype="html">
<source>Save &amp; close</source> <source>Save &amp; close</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">467</context> <context context-type="linenumber">461</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3823219296477075982" datatype="html"> <trans-unit id="3823219296477075982" datatype="html">
<source>Discard</source> <source>Discard</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">469,470</context> <context context-type="linenumber">463,464</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1309556917227148591" datatype="html"> <trans-unit id="1309556917227148591" datatype="html">
<source>Document loading...</source> <source>Document loading...</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">477</context> <context context-type="linenumber">471</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8191371354890763172" datatype="html"> <trans-unit id="8191371354890763172" datatype="html">
<source>Enter Password</source> <source>Enter Password</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
<context context-type="linenumber">531</context> <context context-type="linenumber">525</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5758784066858623886" datatype="html"> <trans-unit id="5758784066858623886" datatype="html">
<source>Error retrieving metadata</source> <source>Error retrieving metadata</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">463</context> <context context-type="linenumber">461</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2218903673684131427" datatype="html"> <trans-unit id="2218903673684131427" datatype="html">
<source>An error occurred loading content: <x id="PH" equiv-text="err.message ?? err.toString()"/></source> <source>An error occurred loading content: <x id="PH" equiv-text="err.message ?? err.toString()"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">566,568</context> <context context-type="linenumber">564,566</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1047,1049</context> <context context-type="linenumber">1045,1047</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6357361810318120957" datatype="html"> <trans-unit id="6357361810318120957" datatype="html">
<source>Document was updated</source> <source>Document was updated</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">708</context> <context context-type="linenumber">706</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5154064822428631306" datatype="html"> <trans-unit id="5154064822428631306" datatype="html">
<source>Document was updated at <x id="PH" equiv-text="formattedModified"/>.</source> <source>Document was updated at <x id="PH" equiv-text="formattedModified"/>.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">709</context> <context context-type="linenumber">707</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8462497568316256794" datatype="html"> <trans-unit id="8462497568316256794" datatype="html">
<source>Reload to discard your local unsaved edits and load the latest remote version.</source> <source>Reload to discard your local unsaved edits and load the latest remote version.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">710</context> <context context-type="linenumber">708</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7967484035994732534" datatype="html"> <trans-unit id="7967484035994732534" datatype="html">
<source>Reload</source> <source>Reload</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">712</context> <context context-type="linenumber">710</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2907037627372942104" datatype="html"> <trans-unit id="2907037627372942104" datatype="html">
<source>Document reloaded with latest changes.</source> <source>Document reloaded with latest changes.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">768</context> <context context-type="linenumber">766</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6435639868943916539" datatype="html"> <trans-unit id="6435639868943916539" datatype="html">
<source>Document reloaded.</source> <source>Document reloaded.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">779</context> <context context-type="linenumber">777</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6142395741265832184" datatype="html"> <trans-unit id="6142395741265832184" datatype="html">
<source>Next document</source> <source>Next document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">881</context> <context context-type="linenumber">879</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="651985345816518480" datatype="html"> <trans-unit id="651985345816518480" datatype="html">
<source>Previous document</source> <source>Previous document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">891</context> <context context-type="linenumber">889</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2885986061416655600" datatype="html"> <trans-unit id="2885986061416655600" datatype="html">
<source>Close document</source> <source>Close document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">899</context> <context context-type="linenumber">897</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/services/open-documents.service.ts</context> <context context-type="sourcefile">src/app/services/open-documents.service.ts</context>
@@ -8782,28 +8752,28 @@
<source>Save document</source> <source>Save document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">906</context> <context context-type="linenumber">904</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1784543155727940353" datatype="html"> <trans-unit id="1784543155727940353" datatype="html">
<source>Save and close / next</source> <source>Save and close / next</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">915</context> <context context-type="linenumber">913</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7427704425579737895" datatype="html"> <trans-unit id="7427704425579737895" datatype="html">
<source>Error retrieving version content</source> <source>Error retrieving version content</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1029</context> <context context-type="linenumber">1027</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="159901853873315050" datatype="html"> <trans-unit id="159901853873315050" datatype="html">
<source>Unsaved Changes</source> <source>Unsaved Changes</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1073</context> <context context-type="linenumber">1071</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/guards/dirty-form.guard.ts</context> <context context-type="sourcefile">src/app/guards/dirty-form.guard.ts</context>
@@ -8826,74 +8796,74 @@
<source>You have unsaved changes to the content of this version.</source> <source>You have unsaved changes to the content of this version.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1074</context> <context context-type="linenumber">1072</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="85184271222513014" datatype="html"> <trans-unit id="85184271222513014" datatype="html">
<source>Switching versions will discard them.</source> <source>Switching versions will discard them.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1075</context> <context context-type="linenumber">1073</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2565707334844767610" datatype="html"> <trans-unit id="2565707334844767610" datatype="html">
<source>Discard and switch</source> <source>Discard and switch</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1077</context> <context context-type="linenumber">1075</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2109314380040637387" datatype="html"> <trans-unit id="2109314380040637387" datatype="html">
<source>Save and switch</source> <source>Save and switch</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1079</context> <context context-type="linenumber">1077</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3456881259945295697" datatype="html"> <trans-unit id="3456881259945295697" datatype="html">
<source>Error retrieving suggestions.</source> <source>Error retrieving suggestions.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1122</context> <context context-type="linenumber">1120</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2194092841814123758" datatype="html"> <trans-unit id="2194092841814123758" datatype="html">
<source>Document &quot;<x id="PH" equiv-text="newValues.title"/>&quot; saved successfully.</source> <source>Document &quot;<x id="PH" equiv-text="newValues.title"/>&quot; saved successfully.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1353</context> <context context-type="linenumber">1347</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1381</context> <context context-type="linenumber">1375</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6626387786259219838" datatype="html"> <trans-unit id="6626387786259219838" datatype="html">
<source>Error saving document &quot;<x id="PH" equiv-text="this.document().title"/>&quot;</source> <source>Error saving document &quot;<x id="PH" equiv-text="this.document().title"/>&quot;</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1387</context> <context context-type="linenumber">1381</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="448882439049417053" datatype="html"> <trans-unit id="448882439049417053" datatype="html">
<source>Error saving document</source> <source>Error saving document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1442</context> <context context-type="linenumber">1436</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8410796510716511826" datatype="html"> <trans-unit id="8410796510716511826" datatype="html">
<source>Do you really want to move the document &quot;<x id="PH" equiv-text="this.document().title"/>&quot; to the trash?</source> <source>Do you really want to move the document &quot;<x id="PH" equiv-text="this.document().title"/>&quot; to the trash?</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1475</context> <context context-type="linenumber">1469</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="282586936710748252" datatype="html"> <trans-unit id="282586936710748252" datatype="html">
<source>Documents can be restored prior to permanent deletion.</source> <source>Documents can be restored prior to permanent deletion.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1476</context> <context context-type="linenumber">1470</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -8904,14 +8874,14 @@
<source>Error deleting document</source> <source>Error deleting document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1497</context> <context context-type="linenumber">1491</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="619486176823357521" datatype="html"> <trans-unit id="619486176823357521" datatype="html">
<source>Reprocess confirm</source> <source>Reprocess confirm</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1517</context> <context context-type="linenumber">1511</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -8922,102 +8892,102 @@
<source>This operation will permanently recreate the archive file for this document.</source> <source>This operation will permanently recreate the archive file for this document.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1518</context> <context context-type="linenumber">1512</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="302054111564709516" datatype="html"> <trans-unit id="302054111564709516" datatype="html">
<source>The archive file will be re-generated with the current settings.</source> <source>The archive file will be re-generated with the current settings.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1519</context> <context context-type="linenumber">1513</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4700389117298802932" datatype="html"> <trans-unit id="4700389117298802932" datatype="html">
<source>Reprocess operation for &quot;<x id="PH" equiv-text="this.document().title"/>&quot; will begin in the background.</source> <source>Reprocess operation for &quot;<x id="PH" equiv-text="this.document().title"/>&quot; will begin in the background.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1532</context> <context context-type="linenumber">1526</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4409560272830824468" datatype="html"> <trans-unit id="4409560272830824468" datatype="html">
<source>Error executing operation</source> <source>Error executing operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1543</context> <context context-type="linenumber">1537</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6030453331794586802" datatype="html"> <trans-unit id="6030453331794586802" datatype="html">
<source>Error downloading document</source> <source>Error downloading document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1607</context> <context context-type="linenumber">1601</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4458954481601077369" datatype="html"> <trans-unit id="4458954481601077369" datatype="html">
<source>Page Fit</source> <source>Page Fit</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1685</context> <context context-type="linenumber">1679</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4663705961777238777" datatype="html"> <trans-unit id="4663705961777238777" datatype="html">
<source>PDF edit operation for &quot;<x id="PH" equiv-text="this.document().title"/>&quot; will begin in the background.</source> <source>PDF edit operation for &quot;<x id="PH" equiv-text="this.document().title"/>&quot; will begin in the background.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1928</context> <context context-type="linenumber">1922</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="9043972994040261999" datatype="html"> <trans-unit id="9043972994040261999" datatype="html">
<source>Error executing PDF edit operation</source> <source>Error executing PDF edit operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1940</context> <context context-type="linenumber">1934</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6172690334763056188" datatype="html"> <trans-unit id="6172690334763056188" datatype="html">
<source>Please enter the current password before attempting to remove it.</source> <source>Please enter the current password before attempting to remove it.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1951</context> <context context-type="linenumber">1945</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="968660764814228922" datatype="html"> <trans-unit id="968660764814228922" datatype="html">
<source>Password removal operation for &quot;<x id="PH" equiv-text="this.document().title"/>&quot; will begin in the background.</source> <source>Password removal operation for &quot;<x id="PH" equiv-text="this.document().title"/>&quot; will begin in the background.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1985</context> <context context-type="linenumber">1979</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2282118435712883014" datatype="html"> <trans-unit id="2282118435712883014" datatype="html">
<source>Error executing password removal operation</source> <source>Error executing password removal operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1999</context> <context context-type="linenumber">1993</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3740891324955700797" datatype="html"> <trans-unit id="3740891324955700797" datatype="html">
<source>Print failed.</source> <source>Print failed.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">2049</context> <context context-type="linenumber">2043</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6457245677384603573" datatype="html"> <trans-unit id="6457245677384603573" datatype="html">
<source>Error loading document for printing.</source> <source>Error loading document for printing.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">2058</context> <context context-type="linenumber">2052</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6085793215710522488" datatype="html"> <trans-unit id="6085793215710522488" datatype="html">
<source>An error occurred loading tiff: <x id="PH" equiv-text="err.toString()"/></source> <source>An error occurred loading tiff: <x id="PH" equiv-text="err.toString()"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">2141</context> <context context-type="linenumber">2135</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">2147</context> <context context-type="linenumber">2141</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4958946940233632319" datatype="html"> <trans-unit id="4958946940233632319" datatype="html">
@@ -12083,130 +12053,123 @@
<context context-type="linenumber">328</context> <context context-type="linenumber">328</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="906679600349814230" datatype="html">
<source>Store Barcode Contents</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">335</context>
</context-group>
</trans-unit>
<trans-unit id="7011909364081812031" datatype="html"> <trans-unit id="7011909364081812031" datatype="html">
<source>AI Enabled</source> <source>AI Enabled</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">342</context> <context context-type="linenumber">335</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8028880048909383956" datatype="html"> <trans-unit id="8028880048909383956" datatype="html">
<source>Consider privacy implications when enabling AI features, especially if using a remote model.</source> <source>Consider privacy implications when enabling AI features, especially if using a remote model.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">346</context> <context context-type="linenumber">339</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8131374115579345652" datatype="html"> <trans-unit id="8131374115579345652" datatype="html">
<source>LLM Embedding Backend</source> <source>LLM Embedding Backend</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">350</context> <context context-type="linenumber">343</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6647708571891295756" datatype="html"> <trans-unit id="6647708571891295756" datatype="html">
<source>LLM Embedding Model</source> <source>LLM Embedding Model</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">358</context> <context context-type="linenumber">351</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="861068592166833023" datatype="html"> <trans-unit id="861068592166833023" datatype="html">
<source>LLM Embedding API Key</source> <source>LLM Embedding API Key</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">365</context> <context context-type="linenumber">358</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2929108042259892948" datatype="html"> <trans-unit id="2929108042259892948" datatype="html">
<source>Used for embeddings when set, otherwise LLM API key is used.</source> <source>Used for embeddings when set, otherwise LLM API key is used.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">367</context> <context context-type="linenumber">360</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3554114880473286122" datatype="html"> <trans-unit id="3554114880473286122" datatype="html">
<source>LLM Embedding Endpoint</source> <source>LLM Embedding Endpoint</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">373</context> <context context-type="linenumber">366</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1044242175651289991" datatype="html"> <trans-unit id="1044242175651289991" datatype="html">
<source>LLM Embedding Chunk Size</source> <source>LLM Embedding Chunk Size</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">380</context> <context context-type="linenumber">373</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7218245223139363113" datatype="html"> <trans-unit id="7218245223139363113" datatype="html">
<source>LLM Context Size</source> <source>LLM Context Size</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">387</context> <context context-type="linenumber">380</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4234495692726214397" datatype="html"> <trans-unit id="4234495692726214397" datatype="html">
<source>LLM Backend</source> <source>LLM Backend</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">394</context> <context context-type="linenumber">387</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7935234833834000002" datatype="html"> <trans-unit id="7935234833834000002" datatype="html">
<source>LLM Model</source> <source>LLM Model</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">402</context> <context context-type="linenumber">395</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1980550530387803165" datatype="html"> <trans-unit id="1980550530387803165" datatype="html">
<source>LLM API Key</source> <source>LLM API Key</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">409</context> <context context-type="linenumber">402</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6126617860376156501" datatype="html"> <trans-unit id="6126617860376156501" datatype="html">
<source>LLM Endpoint</source> <source>LLM Endpoint</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">416</context> <context context-type="linenumber">409</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6572826277249350975" datatype="html"> <trans-unit id="6572826277249350975" datatype="html">
<source>LLM Output Language</source> <source>LLM Output Language</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">423</context> <context context-type="linenumber">416</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3284403507172415792" datatype="html"> <trans-unit id="3284403507172415792" datatype="html">
<source>Language to use for generated AI suggestions. When unset, AI suggestions use the user&apos;s display language if explicitly set.</source> <source>Language to use for generated AI suggestions. When unset, AI suggestions use the user&apos;s display language if explicitly set.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">427</context> <context context-type="linenumber">420</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4493921125434706859" datatype="html"> <trans-unit id="4493921125434706859" datatype="html">
<source>LLM Request Timeout</source> <source>LLM Request Timeout</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">431</context> <context context-type="linenumber">424</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="483994032066441287" datatype="html"> <trans-unit id="483994032066441287" datatype="html">
<source>Timeout in seconds for LLM requests.</source> <source>Timeout in seconds for LLM requests.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/data/paperless-config.ts</context> <context context-type="sourcefile">src/app/data/paperless-config.ts</context>
<context context-type="linenumber">435</context> <context context-type="linenumber">428</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1055686627716339120" datatype="html"> <trans-unit id="1055686627716339120" datatype="html">
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "paperless-ngx-ui", "name": "paperless-ngx-ui",
"version": "3.3.1", "version": "3.2.1",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"ng": "ng", "ng": "ng",
@@ -26,7 +26,7 @@
<div ngbDropdownMenu aria-labelledby="suggestionsDropdown" class="shadow suggestions-dropdown"> <div ngbDropdownMenu aria-labelledby="suggestionsDropdown" class="shadow suggestions-dropdown">
<div class="list-group list-group-flush small pb-0"> <div class="list-group list-group-flush small pb-0">
@if (novelSuggestions === 0 && fieldSuggestions === 0) { @if (novelSuggestions === 0 && reusableSuggestions === 0) {
<div class="list-group-item text-muted fst-italic"> <div class="list-group-item text-muted fst-italic">
<small class="text-muted small fst-italic" i18n>No novel suggestions</small> <small class="text-muted small fst-italic" i18n>No novel suggestions</small>
</div> </div>
@@ -49,9 +49,9 @@
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addCorrespondent.emit(correspondent)">{{ correspondent }}</button> <button type="button" class="list-group-item list-group-item-action bg-light" (click)="addCorrespondent.emit(correspondent)">{{ correspondent }}</button>
} }
} }
@if (fieldSuggestions > 0) { @if (reusableSuggestions > 0) {
<div class="list-group-item text-muted fst-italic"> <div class="list-group-item text-muted fst-italic">
<small class="text-muted small fst-italic" i18n>{fieldSuggestions, plural, =1 {1 suggestion available below} other {{{fieldSuggestions}} suggestions available below}}</small> <small class="text-muted small fst-italic" i18n>{reusableSuggestions, plural, =1 {1 existing value suggested below} other {{{reusableSuggestions}} existing values suggested below}}</small>
</div> </div>
} }
</div> </div>
@@ -84,7 +84,7 @@ describe('SuggestionsDropdownComponent', () => {
fixture.detectChanges() fixture.detectChanges()
expect(fixture.nativeElement.textContent).toContain( expect(fixture.nativeElement.textContent).toContain(
'2 suggestions available below' '2 existing values suggested below'
) )
expect(fixture.nativeElement.textContent).not.toContain( expect(fixture.nativeElement.textContent).not.toContain(
'No novel suggestions' 'No novel suggestions'
@@ -108,7 +108,7 @@ describe('SuggestionsDropdownComponent', () => {
expect(component.totalSuggestions).toBe(4) expect(component.totalSuggestions).toBe(4)
expect(fixture.nativeElement.textContent).toContain('Arbitration') expect(fixture.nativeElement.textContent).toContain('Arbitration')
expect(fixture.nativeElement.textContent).toContain( expect(fixture.nativeElement.textContent).toContain(
'2 suggestions available below' '2 existing values suggested below'
) )
}) })
@@ -125,46 +125,10 @@ describe('SuggestionsDropdownComponent', () => {
}) })
expect(component.novelSuggestions).toBe(0) expect(component.novelSuggestions).toBe(0)
expect(component.totalSuggestions).toBe(6) expect(component.totalSuggestions).toBe(5)
fixture.componentRef.setInput('appliedStoragePath', 7) fixture.componentRef.setInput('appliedStoragePath', 7)
expect(component.totalSuggestions).toBe(5) expect(component.totalSuggestions).toBe(4)
})
it('should count title and dates as field suggestions without calling them existing values', () => {
fixture.componentRef.setInput('aiEnabled', true)
fixture.componentRef.setInput('fetchedSources', [SuggestionSource.ML])
fixture.componentRef.setInput('suggestions', {
title: 'Suggested title',
dates: ['2026-01-04', '2026-02-01', '2026-03-01'],
correspondents: [1, 2, 3, 4],
document_types: [1, 2, 3, 4],
tags: [1, 2, 3, 4, 5, 6, 7, 8],
})
fixture.detectChanges()
component.clickSuggest()
fixture.detectChanges()
expect(component.reusableSuggestions).toBe(16)
expect(component.fieldSuggestions).toBe(20)
expect(component.totalSuggestions).toBe(20)
expect(fixture.nativeElement.textContent).toContain(
'20 suggestions available below'
)
expect(fixture.nativeElement.textContent).not.toContain('existing value')
})
it('should not count title or date suggestions matching the current values', () => {
fixture.componentRef.setInput('suggestions', {
title: 'Current title',
dates: ['2026-01-04', '2026-02-01'],
})
expect(component.fieldSuggestions).toBe(3)
fixture.componentRef.setInput('appliedTitle', 'Current title')
fixture.componentRef.setInput('appliedCreated', '2026-01-04')
expect(component.fieldSuggestions).toBe(1)
expect(component.totalSuggestions).toBe(1)
}) })
it('should show when a completed request returned no suggestions', () => { it('should show when a completed request returned no suggestions', () => {
@@ -181,28 +145,6 @@ describe('SuggestionsDropdownComponent', () => {
expect(fixture.nativeElement.textContent).toContain('No suggestions') expect(fixture.nativeElement.textContent).toContain('No suggestions')
}) })
it('should wait for all pending responses before showing the empty state', () => {
fixture.componentRef.setInput('aiEnabled', true)
fixture.componentRef.setInput('source', SuggestionSource.Both)
fixture.componentRef.setInput('fetchedSources', [SuggestionSource.ML])
fixture.componentRef.setInput('suggestions', { tags: [] })
fixture.componentRef.setInput('loading', true)
fixture.detectChanges()
expect(component.noSuggestions).toBeFalsy()
expect(fixture.nativeElement.textContent).not.toContain('No suggestions')
expect(
fixture.nativeElement.querySelector('[role="status"]')
).not.toBeNull()
fixture.componentRef.setInput('loading', false)
fixture.detectChanges()
expect(component.noSuggestions).toBeTruthy()
expect(fixture.nativeElement.textContent).toContain('No suggestions')
expect(fixture.nativeElement.querySelector('[role="status"]')).toBeNull()
})
it('should not show the empty state before a request or with suggestions', () => { it('should not show the empty state before a request or with suggestions', () => {
expect(component.noSuggestions).toBeFalsy() expect(component.noSuggestions).toBeFalsy()
@@ -34,8 +34,6 @@ export class SuggestionsDropdownComponent {
readonly appliedCorrespondent = input<number>(null) readonly appliedCorrespondent = input<number>(null)
readonly appliedDocumentType = input<number>(null) readonly appliedDocumentType = input<number>(null)
readonly appliedStoragePath = input<number>(null) readonly appliedStoragePath = input<number>(null)
readonly appliedTitle = input<string>(null)
readonly appliedCreated = input<string>(null)
@Output() @Output()
getSuggestions: EventEmitter<SuggestionSource> = new EventEmitter() getSuggestions: EventEmitter<SuggestionSource> = new EventEmitter()
@@ -130,28 +128,7 @@ export class SuggestionsDropdownComponent {
} }
get totalSuggestions(): number { get totalSuggestions(): number {
return this.novelSuggestions + this.fieldSuggestions return this.novelSuggestions + this.reusableSuggestions
}
get fieldSuggestions(): number {
return (
this.reusableSuggestions +
this.unappliedTitleSuggestions +
this.unappliedDateSuggestions
)
}
// hide a title or date suggestion equal to the current value
private get unappliedTitleSuggestions(): number {
const title = this.suggestions()?.title
return title && title !== this.appliedTitle() ? 1 : 0
}
private get unappliedDateSuggestions(): number {
const created = this.appliedCreated()
return (this.suggestions()?.dates ?? []).filter(
(date) => !created || date !== created
).length
} }
private countUnapplied(suggested: number[], applied: number[]): number { private countUnapplied(suggested: number[], applied: number[]): number {
@@ -162,7 +139,6 @@ export class SuggestionsDropdownComponent {
get noSuggestions(): boolean { get noSuggestions(): boolean {
const suggestions = this.suggestions() const suggestions = this.suggestions()
return ( return (
!this.loading() &&
suggestions != null && suggestions != null &&
!suggestions.title && !suggestions.title &&
!suggestions.tags?.length && !suggestions.tags?.length &&
@@ -1,46 +0,0 @@
<table class="table table-borderless align-baseline">
<thead>
<tr>
<th i18n>Page</th>
<th i18n>Type</th>
<th i18n>Content</th>
<th></th>
</tr>
</thead>
<tbody>
@for (barcode of barcodes(); track $index) {
<tr>
<td>{{ barcode.page }}</td>
<td class="text-nowrap">{{ barcode.format }}</td>
<td class="text-break">
@if (isLink(barcode.value)) {
<a
[href]="barcode.value"
target="_blank"
rel="noopener noreferrer nofollow"
>{{ barcode.value }}</a
>
} @else {
{{ barcode.value }}
}
</td>
<td class="text-end">
<button
type="button"
class="btn btn-sm btn-outline-primary"
(click)="copy($index)"
title="Copy content"
i18n-title
>
@if (copiedIndex() === $index) {
<i-bs name="clipboard-check"></i-bs>
} @else {
<i-bs name="clipboard"></i-bs>
}
<span class="visually-hidden" i18n>Copy content</span>
</button>
</td>
</tr>
}
</tbody>
</table>
@@ -1,73 +0,0 @@
import { Clipboard } from '@angular/cdk/clipboard'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
import { DocumentBarcodesComponent } from './document-barcodes.component'
const barcodes = [
{ page: 1, value: 'ASN00123', format: 'Code128' },
{ page: 2, value: 'https://example.com/invoice/4711', format: 'QRCode' },
{ page: 2, value: 'javascript:alert(1)', format: 'QRCode' },
]
describe('DocumentBarcodesComponent', () => {
let component: DocumentBarcodesComponent
let fixture: ComponentFixture<DocumentBarcodesComponent>
let clipboard: Clipboard
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [
DocumentBarcodesComponent,
NgxBootstrapIconsModule.pick(allIcons),
],
}).compileComponents()
fixture = TestBed.createComponent(DocumentBarcodesComponent)
component = fixture.componentInstance
clipboard = TestBed.inject(Clipboard)
fixture.componentRef.setInput('barcodes', barcodes)
fixture.detectChanges()
})
it('should display all barcodes', () => {
const rows = fixture.nativeElement.querySelectorAll('tbody tr')
expect(rows).toHaveLength(3)
expect(rows[0].textContent).toContain('ASN00123')
expect(rows[0].textContent).toContain('Code128')
})
it('should only link http(s) values', () => {
const links = fixture.nativeElement.querySelectorAll('tbody a')
expect(links).toHaveLength(1)
expect(links[0].getAttribute('href')).toEqual(
'https://example.com/invoice/4711'
)
expect(links[0].getAttribute('target')).toEqual('_blank')
})
it('should copy a value and show feedback', () => {
jest.useFakeTimers()
const copySpy = jest.spyOn(clipboard, 'copy').mockReturnValue(true)
const buttons = fixture.nativeElement.querySelectorAll('tbody button')
buttons[0].click()
fixture.detectChanges()
expect(copySpy).toHaveBeenCalledWith('ASN00123')
expect(component.copiedIndex()).toEqual(0)
expect(buttons[0].querySelector('i-bs').getAttribute('name')).toEqual(
'clipboard-check'
)
jest.advanceTimersByTime(3000)
fixture.detectChanges()
expect(component.copiedIndex()).toBeNull()
expect(buttons[0].querySelector('i-bs').getAttribute('name')).toEqual(
'clipboard'
)
jest.useRealTimers()
})
it('should not show feedback if copying failed', () => {
jest.spyOn(clipboard, 'copy').mockReturnValue(false)
component.copy(1)
expect(component.copiedIndex()).toBeNull()
})
})
@@ -1,38 +0,0 @@
import { Clipboard } from '@angular/cdk/clipboard'
import { Component, inject, input, OnDestroy, signal } from '@angular/core'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { DocumentBarcode } from 'src/app/data/document-barcode'
@Component({
selector: 'pngx-document-barcodes',
templateUrl: './document-barcodes.component.html',
imports: [NgxBootstrapIconsModule],
})
export class DocumentBarcodesComponent implements OnDestroy {
private readonly clipboard = inject(Clipboard)
readonly barcodes = input<DocumentBarcode[]>([])
readonly copiedIndex = signal<number>(null)
private copyTimeout: ReturnType<typeof setTimeout>
public isLink(value: string): boolean {
try {
const url = new URL(value.trim())
return ['http:', 'https:'].includes(url.protocol) && !!url.host
} catch {
return false
}
}
public copy(index: number) {
if (!this.clipboard.copy(this.barcodes()[index].value)) return
this.copiedIndex.set(index)
clearTimeout(this.copyTimeout)
this.copyTimeout = setTimeout(() => this.copiedIndex.set(null), 3000)
}
ngOnDestroy(): void {
clearTimeout(this.copyTimeout)
}
}
@@ -141,8 +141,6 @@
[appliedCorrespondent]="documentForm.value.correspondent" [appliedCorrespondent]="documentForm.value.correspondent"
[appliedDocumentType]="documentForm.value.document_type" [appliedDocumentType]="documentForm.value.document_type"
[appliedStoragePath]="documentForm.value.storage_path" [appliedStoragePath]="documentForm.value.storage_path"
[appliedTitle]="documentForm.value.title"
[appliedCreated]="documentForm.value.created"
(getSuggestions)="getSuggestions($event)" (getSuggestions)="getSuggestions($event)"
(sourceChange)="suggestionSourceOverride.set($event)" (sourceChange)="suggestionSourceOverride.set($event)"
(addTag)="createTag($event)" (addTag)="createTag($event)"
@@ -356,10 +354,6 @@
</table> </table>
} }
@if (metadata()?.barcodes?.length > 0) {
<h6 i18n>Barcodes</h6>
<pngx-document-barcodes [barcodes]="metadata().barcodes"></pngx-document-barcodes>
}
@if (metadata()?.original_metadata?.length > 0) { @if (metadata()?.original_metadata?.length > 0) {
<pngx-metadata-collapse i18n-title title="Original document metadata" [metadata]="metadata()?.original_metadata"></pngx-metadata-collapse> <pngx-metadata-collapse i18n-title title="Original document metadata" [metadata]="metadata()?.original_metadata"></pngx-metadata-collapse>
} }
@@ -662,45 +662,6 @@ describe('DocumentDetailComponent', () => {
) )
}) })
it.each([
['tag', 'createTag', 'tags', 'suggested_tags'],
[
'document type',
'createDocumentType',
'document_type',
'suggested_document_types',
],
[
'correspondent',
'createCorrespondent',
'correspondent',
'suggested_correspondents',
],
])(
'should create a %s after ML-only suggestions',
(_, method, field, suggestedField) => {
initNormally()
component.suggestions.set({ tags: [1] })
let openModal: NgbModalRef
modalService.activeInstances.subscribe((modal) => (openModal = modal[0]))
component[method]('New value')
openModal.componentInstance.succeeded.next({
id: 12,
name: 'New value',
is_inbox_tag: false,
color: '#ff0000',
text_color: '#000000',
})
if (field === 'tags') {
expect(component.tagsInput.value).toContain(12)
} else {
expect(component.documentForm.get(field).value).toBe(12)
}
expect(component.suggestions()[suggestedField]).toEqual([])
}
)
it('should support creating storage path', () => { it('should support creating storage path', () => {
initNormally() initNormally()
let openModal: NgbModalRef let openModal: NgbModalRef
@@ -135,7 +135,6 @@ import { ShareLinksDialogComponent } from '../common/share-links-dialog/share-li
import { SuggestionsDropdownComponent } from '../common/suggestions-dropdown/suggestions-dropdown.component' import { SuggestionsDropdownComponent } from '../common/suggestions-dropdown/suggestions-dropdown.component'
import { DocumentNotesComponent } from '../document-notes/document-notes.component' import { DocumentNotesComponent } from '../document-notes/document-notes.component'
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component' import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
import { DocumentBarcodesComponent } from './document-barcodes/document-barcodes.component'
import { DocumentHistoryComponent } from './document-history/document-history.component' import { DocumentHistoryComponent } from './document-history/document-history.component'
import { DocumentVersionDropdownComponent } from './document-version-dropdown/document-version-dropdown.component' import { DocumentVersionDropdownComponent } from './document-version-dropdown/document-version-dropdown.component'
import { MetadataCollapseComponent } from './metadata-collapse/metadata-collapse.component' import { MetadataCollapseComponent } from './metadata-collapse/metadata-collapse.component'
@@ -178,7 +177,6 @@ interface IncomingDocumentUpdate {
DateComponent, DateComponent,
DocumentLinkComponent, DocumentLinkComponent,
MetadataCollapseComponent, MetadataCollapseComponent,
DocumentBarcodesComponent,
PermissionsFormComponent, PermissionsFormComponent,
SelectComponent, SelectComponent,
TagsComponent, TagsComponent,
@@ -1154,7 +1152,7 @@ export class DocumentDetailComponent
if (this.suggestions()) { if (this.suggestions()) {
this.suggestions.set({ this.suggestions.set({
...this.suggestions(), ...this.suggestions(),
suggested_tags: (this.suggestions().suggested_tags ?? []).filter( suggested_tags: this.suggestions().suggested_tags.filter(
(tag) => tag !== newTag.name (tag) => tag !== newTag.name
), ),
}) })
@@ -1193,12 +1191,10 @@ export class DocumentDetailComponent
this.documentForm.get('document_type').setValue(newDocumentType.id) this.documentForm.get('document_type').setValue(newDocumentType.id)
this.documentForm.get('document_type').markAsDirty() this.documentForm.get('document_type').markAsDirty()
if (this.suggestions()) { if (this.suggestions()) {
this.suggestions.set({ this.suggestions().suggested_document_types =
...this.suggestions(), this.suggestions().suggested_document_types.filter(
suggested_document_types: ( (dt) => dt !== newName
this.suggestions().suggested_document_types ?? [] )
).filter((dt) => dt !== newName),
})
} }
}) })
} }
@@ -1225,12 +1221,10 @@ export class DocumentDetailComponent
this.documentForm.get('correspondent').setValue(newCorrespondent.id) this.documentForm.get('correspondent').setValue(newCorrespondent.id)
this.documentForm.get('correspondent').markAsDirty() this.documentForm.get('correspondent').markAsDirty()
if (this.suggestions()) { if (this.suggestions()) {
this.suggestions.set({ this.suggestions().suggested_correspondents =
...this.suggestions(), this.suggestions().suggested_correspondents.filter(
suggested_correspondents: ( (c) => c !== newName
this.suggestions().suggested_correspondents ?? [] )
).filter((c) => c !== newName),
})
} }
}) })
} }
@@ -484,22 +484,6 @@ describe('FilterEditorComponent', () => {
expect(component.textFilter).toBeNull() expect(component.textFilter).toBeNull()
}) })
it('should ingest title filter rules alongside a fulltext query with date created', () => {
component.filterRules = [
{
rule_type: FILTER_SIMPLE_TITLE,
value: 'foo',
},
{
rule_type: FILTER_FULLTEXT_QUERY,
value: 'created:[-1 week to now]',
},
]
expect(component.dateCreatedRelativeDate).toEqual(1) // RELATIVE_DATE_QUERYSTRINGS['-1 week to now']
expect(component.textFilter).toEqual('foo')
expect(component.textFilterTarget).toEqual('title') // TEXT_FILTER_TARGET_TITLE
})
it('should ingest text filter rules for fulltext query that include date added', () => { it('should ingest text filter rules for fulltext query that include date added', () => {
expect(component.dateAddedRelativeDate).toBeNull() expect(component.dateAddedRelativeDate).toBeNull()
component.filterRules = [ component.filterRules = [
@@ -1861,7 +1845,7 @@ describe('FilterEditorComponent', () => {
]) ])
}) })
it('should keep text filtering separate from date created relative date', () => { it('should carry over text filtering on date created with relative date', () => {
component.textFilter = 'foo' component.textFilter = 'foo'
const dateCreatedDropdown = fixture.debugElement.queryAll( const dateCreatedDropdown = fixture.debugElement.queryAll(
By.directive(DatesDropdownComponent) By.directive(DatesDropdownComponent)
@@ -1871,18 +1855,14 @@ describe('FilterEditorComponent', () => {
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{
rule_type: FILTER_SIMPLE_TEXT,
value: 'foo',
},
{ {
rule_type: FILTER_FULLTEXT_QUERY, rule_type: FILTER_FULLTEXT_QUERY,
value: 'created:[-1 week to now]', value: 'foo,created:[-1 week to now]',
}, },
]) ])
}) })
it('should keep text filtering separate from created and added relative dates', () => { it('should carry over text filtering once with created and added relative dates', () => {
component.textFilter = 'foo' component.textFilter = 'foo'
const datesDropdown = fixture.debugElement.query( const datesDropdown = fixture.debugElement.query(
By.directive(DatesDropdownComponent) By.directive(DatesDropdownComponent)
@@ -1893,18 +1873,14 @@ describe('FilterEditorComponent', () => {
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{
rule_type: FILTER_SIMPLE_TEXT,
value: 'foo',
},
{ {
rule_type: FILTER_FULLTEXT_QUERY, rule_type: FILTER_FULLTEXT_QUERY,
value: 'created:[-1 week to now],added:[-1 month to now]', value: 'foo,created:[-1 week to now],added:[-1 month to now]',
}, },
]) ])
}) })
it('should keep legacy title filters as a title search when adding a created relative date', () => { it('should convert legacy title filters into full text query when adding a created relative date', () => {
component.filterRules = [ component.filterRules = [
{ {
rule_type: FILTER_TITLE, rule_type: FILTER_TITLE,
@@ -1919,18 +1895,14 @@ describe('FilterEditorComponent', () => {
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{
rule_type: FILTER_SIMPLE_TITLE,
value: 'foo',
},
{ {
rule_type: FILTER_FULLTEXT_QUERY, rule_type: FILTER_FULLTEXT_QUERY,
value: 'created:[-1 week to now]', value: 'foo,created:[-1 week to now]',
}, },
]) ])
}) })
it('should keep simple title filters as a title search when adding a created relative date', () => { it('should convert simple title filters into full text query when adding a created relative date', () => {
component.filterRules = [ component.filterRules = [
{ {
rule_type: FILTER_SIMPLE_TITLE, rule_type: FILTER_SIMPLE_TITLE,
@@ -1945,13 +1917,9 @@ describe('FilterEditorComponent', () => {
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{
rule_type: FILTER_SIMPLE_TITLE,
value: 'foo',
},
{ {
rule_type: FILTER_FULLTEXT_QUERY, rule_type: FILTER_FULLTEXT_QUERY,
value: 'created:[-1 week to now]', value: 'foo,created:[-1 week to now]',
}, },
]) ])
}) })
@@ -2037,7 +2005,7 @@ describe('FilterEditorComponent', () => {
]) ])
}) })
it('should keep text filtering separate from date added relative date', () => { it('should carry over text filtering on date added with relative date', () => {
component.textFilter = 'foo' component.textFilter = 'foo'
const datesDropdown = fixture.debugElement.query( const datesDropdown = fixture.debugElement.query(
By.directive(DatesDropdownComponent) By.directive(DatesDropdownComponent)
@@ -2047,13 +2015,9 @@ describe('FilterEditorComponent', () => {
fixture.detectChanges() fixture.detectChanges()
tick(400) tick(400)
expect(component.filterRules).toEqual([ expect(component.filterRules).toEqual([
{
rule_type: FILTER_SIMPLE_TEXT,
value: 'foo',
},
{ {
rule_type: FILTER_FULLTEXT_QUERY, rule_type: FILTER_FULLTEXT_QUERY,
value: 'added:[-1 week to now]', value: 'foo,added:[-1 week to now]',
}, },
]) ])
}) })
@@ -1083,6 +1083,23 @@ export class FilterEditorComponent
(fr) => fr.rule_type == FILTER_FULLTEXT_QUERY (fr) => fr.rule_type == FILTER_FULLTEXT_QUERY
) )
// if had a title / content search and added a relative date we need to carry it over...
if (
!existingRule &&
this._textFilter?.length > 0 &&
(this.textFilterTarget == TEXT_FILTER_TARGET_TITLE_CONTENT ||
this.textFilterTarget == TEXT_FILTER_TARGET_TITLE)
) {
existingRule = filterRules.find(
(fr) =>
fr.rule_type == FILTER_TITLE_CONTENT ||
fr.rule_type == FILTER_SIMPLE_TEXT ||
fr.rule_type == FILTER_TITLE ||
fr.rule_type == FILTER_SIMPLE_TITLE
)
existingRule.rule_type = FILTER_FULLTEXT_QUERY
}
let queryArgs = existingRule?.value.split(',') ?? [] let queryArgs = existingRule?.value.split(',') ?? []
if (this.dateCreatedRelativeDate !== null) { if (this.dateCreatedRelativeDate !== null) {
const rd = RELATIVE_DATE_QUERYSTRINGS.find( const rd = RELATIVE_DATE_QUERYSTRINGS.find(
-7
View File
@@ -1,7 +0,0 @@
export interface DocumentBarcode {
page: number
value: string
format: string
}
-4
View File
@@ -1,5 +1,3 @@
import { DocumentBarcode } from './document-barcode'
export interface DocumentMetadata { export interface DocumentMetadata {
original_checksum?: string original_checksum?: string
@@ -14,6 +12,4 @@ export interface DocumentMetadata {
has_archive_version?: boolean has_archive_version?: boolean
lang?: string lang?: string
barcodes?: DocumentBarcode[]
} }
-8
View File
@@ -330,13 +330,6 @@ export const PaperlessConfigOptions: ConfigOption[] = [
config_key: 'PAPERLESS_CONSUMER_TAG_BARCODE_SPLIT', config_key: 'PAPERLESS_CONSUMER_TAG_BARCODE_SPLIT',
category: ConfigCategory.Barcode, category: ConfigCategory.Barcode,
}, },
{
key: 'barcode_store_values',
title: $localize`Store Barcode Contents`,
type: ConfigOptionType.Boolean,
config_key: 'PAPERLESS_CONSUMER_STORE_BARCODE_VALUES',
category: ConfigCategory.Barcode,
},
{ {
key: 'ai_enabled', key: 'ai_enabled',
title: $localize`AI Enabled`, title: $localize`AI Enabled`,
@@ -465,7 +458,6 @@ export interface PaperlessConfig extends ObjectWithId {
barcode_enable_tag: boolean barcode_enable_tag: boolean
barcode_tag_mapping: object barcode_tag_mapping: object
barcode_tag_split: boolean barcode_tag_split: boolean
barcode_store_values: boolean
remote_ocr_engine: string remote_ocr_engine: string
remote_ocr_api_key: string remote_ocr_api_key: string
remote_ocr_endpoint: string remote_ocr_endpoint: string
+1 -1
View File
@@ -8,7 +8,7 @@ export const environment = {
apiVersion: '10', // match src/paperless/settings.py apiVersion: '10', // match src/paperless/settings.py
appTitle: DEFAULT_APP_TITLE, appTitle: DEFAULT_APP_TITLE,
tag: 'prod', tag: 'prod',
version: '3.3.1', version: '3.2.1',
webSocketHost: window.location.host, webSocketHost: window.location.host,
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
webSocketBaseUrl: base_url.pathname + 'ws/', webSocketBaseUrl: base_url.pathname + 'ws/',
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
Loaded 100 of 248 files, more files were not shown because too many files have changed in this diff. Show more