mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-31 20:15:44 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c40849e9bb | ||
|
|
f4358cef53 | ||
|
|
2cb04b0b8b |
No files matched your search
@@ -10,11 +10,9 @@ if [[ -n "${PAPERLESS_CONSUMER_DISABLE}" ]]; then
|
|||||||
else
|
else
|
||||||
cd ${PAPERLESS_SRC_DIR}
|
cd ${PAPERLESS_SRC_DIR}
|
||||||
|
|
||||||
# Django system checks already ran once in init-system-checks, skip repeating them
|
|
||||||
|
|
||||||
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
||||||
exec python3 manage.py document_consumer --skip-checks
|
exec python3 manage.py document_consumer
|
||||||
else
|
else
|
||||||
exec s6-setuidgid paperless python3 manage.py document_consumer --skip-checks
|
exec s6-setuidgid paperless python3 manage.py document_consumer
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
cd ${PAPERLESS_SRC_DIR}
|
cd ${PAPERLESS_SRC_DIR}
|
||||||
|
|
||||||
# Django system checks already ran once in init-system-checks, skip repeating them
|
|
||||||
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
||||||
exec /usr/local/bin/celery --skip-checks --app paperless beat --loglevel INFO
|
exec /usr/local/bin/celery --app paperless beat --loglevel INFO
|
||||||
else
|
else
|
||||||
exec s6-setuidgid paperless /usr/local/bin/celery --skip-checks --app paperless beat --loglevel INFO
|
exec s6-setuidgid paperless /usr/local/bin/celery --app paperless beat --loglevel INFO
|
||||||
fi
|
fi
|
||||||
@@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
cd ${PAPERLESS_SRC_DIR}
|
cd ${PAPERLESS_SRC_DIR}
|
||||||
|
|
||||||
# Django system checks already ran once in init-system-checks, skip repeating them
|
|
||||||
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
||||||
exec /usr/local/bin/celery --skip-checks --app paperless worker --loglevel INFO --without-mingle --without-gossip
|
exec /usr/local/bin/celery --app paperless worker --loglevel INFO --without-mingle --without-gossip
|
||||||
else
|
else
|
||||||
exec s6-setuidgid paperless /usr/local/bin/celery --skip-checks --app paperless worker --loglevel INFO --without-mingle --without-gossip
|
exec s6-setuidgid paperless /usr/local/bin/celery --app paperless worker --loglevel INFO --without-mingle --without-gossip
|
||||||
fi
|
fi
|
||||||
@@ -1,29 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## paperless-ngx 3.4.1
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
- Fix the id\_\_ schemae in the right place [@shamoon](https://github.com/shamoon) ([#14604](https://github.com/paperless-ngx/paperless-ngx/pull/14604))
|
|
||||||
- Fix: drop redundant change perms checks on cards open button [@shamoon](https://github.com/shamoon) ([#14601](https://github.com/paperless-ngx/paperless-ngx/pull/14601))
|
|
||||||
- Tweak/fix: make new pdf controls mostly hidden [@shamoon](https://github.com/shamoon) ([#14595](https://github.com/paperless-ngx/paperless-ngx/pull/14595))
|
|
||||||
- Tweak/fix: move preview button in doc list [@shamoon](https://github.com/shamoon) ([#14594](https://github.com/paperless-ngx/paperless-ngx/pull/14594))
|
|
||||||
- Fix: checksum light mode display and cf dropdown mobile position [@shamoon](https://github.com/shamoon) ([#14590](https://github.com/paperless-ngx/paperless-ngx/pull/14590))
|
|
||||||
|
|
||||||
### All App Changes
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>6 changes</summary>
|
|
||||||
|
|
||||||
- Fix the id\_\_ schemae in the right place [@shamoon](https://github.com/shamoon) ([#14604](https://github.com/paperless-ngx/paperless-ngx/pull/14604))
|
|
||||||
- Fix: drop redundant change perms checks on cards open button [@shamoon](https://github.com/shamoon) ([#14601](https://github.com/paperless-ngx/paperless-ngx/pull/14601))
|
|
||||||
- Chore: Improve idle memory via more lazy imports [@stumpylog](https://github.com/stumpylog) ([#14599](https://github.com/paperless-ngx/paperless-ngx/pull/14599))
|
|
||||||
- Tweak/fix: make new pdf controls mostly hidden [@shamoon](https://github.com/shamoon) ([#14595](https://github.com/paperless-ngx/paperless-ngx/pull/14595))
|
|
||||||
- Tweak/fix: move preview button in doc list [@shamoon](https://github.com/shamoon) ([#14594](https://github.com/paperless-ngx/paperless-ngx/pull/14594))
|
|
||||||
- Fix: checksum light mode display and cf dropdown mobile position [@shamoon](https://github.com/shamoon) ([#14590](https://github.com/paperless-ngx/paperless-ngx/pull/14590))
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## paperless-ngx 3.4.0
|
## paperless-ngx 3.4.0
|
||||||
|
|
||||||
### Features / Enhancements
|
### Features / Enhancements
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "paperless-ngx"
|
name = "paperless-ngx"
|
||||||
version = "3.4.1"
|
version = "3.4.0"
|
||||||
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\
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ def configure_environment(instance_root: Path) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def seed_database() -> None:
|
def seed_database() -> None:
|
||||||
from django.contrib.auth.models import Permission
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@@ -64,18 +63,11 @@ def seed_database() -> None:
|
|||||||
username="playwright",
|
username="playwright",
|
||||||
password="playwright", # NOSONAR
|
password="playwright", # NOSONAR
|
||||||
)
|
)
|
||||||
viewer = User.objects.create_user(
|
User.objects.create_user(
|
||||||
username="viewer",
|
username="viewer",
|
||||||
password="viewer", # NOSONAR
|
password="viewer", # NOSONAR
|
||||||
)
|
)
|
||||||
|
|
||||||
viewer.user_permissions.add(
|
|
||||||
Permission.objects.get(
|
|
||||||
content_type__app_label="documents",
|
|
||||||
codename="view_uisettings",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
inbox = Tag.objects.create(name="Inbox", is_inbox_tag=True, owner=admin)
|
inbox = Tag.objects.create(name="Inbox", is_inbox_tag=True, owner=admin)
|
||||||
quick_filter = Tag.objects.create(name="Another Sample Tag", owner=admin)
|
quick_filter = Tag.objects.create(name="Another Sample Tag", owner=admin)
|
||||||
Tag.objects.create(name="TagWithPartial", owner=admin)
|
Tag.objects.create(name="TagWithPartial", owner=admin)
|
||||||
|
|||||||
@@ -80,21 +80,12 @@ test('should show a list of notes', async ({ page }) => {
|
|||||||
|
|
||||||
test('should support quick filters', async ({ page }) => {
|
test('should support quick filters', async ({ page }) => {
|
||||||
await page.goto('/documents/1/details')
|
await page.goto('/documents/1/details')
|
||||||
// filter button is available before tags have loaded
|
|
||||||
const selectedTags = page.locator('pngx-input-tags .ng-value pngx-tag')
|
|
||||||
await expect(selectedTags).toHaveCount(2)
|
|
||||||
await expect(
|
|
||||||
selectedTags.getByText('Another Sample Tag', { exact: true })
|
|
||||||
).toBeVisible()
|
|
||||||
await expect(selectedTags.getByText('Inbox', { exact: true })).toBeVisible()
|
|
||||||
await page
|
await page
|
||||||
.getByRole('button', { name: 'Filter documents with these Tags' })
|
.getByRole('button', { name: 'Filter documents with these Tags' })
|
||||||
.click()
|
.click()
|
||||||
await expect(page).toHaveURL((url) => {
|
await expect(page).toHaveURL(
|
||||||
const tags = url.searchParams.get('tags__id__all')?.split(',').sort()
|
/tags__id__all=2,1&sort=created&reverse=1&page=1/
|
||||||
return url.pathname === '/documents' && tags?.join(',') === '1,2'
|
)
|
||||||
})
|
|
||||||
await expect(page.locator('pngx-document-list')).toHaveText(/one document/i)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should finish reloading the preview after a remote document update', async ({
|
test('should finish reloading the preview after a remote document update', async ({
|
||||||
|
|||||||
@@ -6,15 +6,8 @@ test.use({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
const settingsLoaded = page.waitForResponse((response) =>
|
|
||||||
response.url().endsWith('/api/ui_settings/')
|
|
||||||
)
|
|
||||||
await page.goto('/dashboard')
|
|
||||||
expect((await settingsLoaded).status()).toBe(200)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should not allow user to edit settings', async ({ page }) => {
|
test('should not allow user to edit settings', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(page.getByRole('link', { name: 'Settings' })).not.toBeAttached()
|
await expect(page.getByRole('link', { name: 'Settings' })).not.toBeAttached()
|
||||||
await page.goto('/settings')
|
await page.goto('/settings')
|
||||||
await expect(page.locator('body')).toHaveText(
|
await expect(page.locator('body')).toHaveText(
|
||||||
@@ -23,6 +16,7 @@ test('should not allow user to edit settings', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('should not allow user to view documents', async ({ page }) => {
|
test('should not allow user to view documents', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('nav').getByRole('link', { name: 'Documents' })
|
page.locator('nav').getByRole('link', { name: 'Documents' })
|
||||||
).not.toBeAttached()
|
).not.toBeAttached()
|
||||||
@@ -37,6 +31,7 @@ test('should not allow user to view documents', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('should not allow user to view correspondents', async ({ page }) => {
|
test('should not allow user to view correspondents', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('link', { name: 'Attributes' })
|
page.getByRole('link', { name: 'Attributes' })
|
||||||
).not.toBeAttached()
|
).not.toBeAttached()
|
||||||
@@ -47,6 +42,7 @@ test('should not allow user to view correspondents', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('should not allow user to view tags', async ({ page }) => {
|
test('should not allow user to view tags', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('link', { name: 'Attributes' })
|
page.getByRole('link', { name: 'Attributes' })
|
||||||
).not.toBeAttached()
|
).not.toBeAttached()
|
||||||
@@ -57,6 +53,7 @@ test('should not allow user to view tags', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('should not allow user to view document types', async ({ page }) => {
|
test('should not allow user to view document types', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('link', { name: 'Attributes' })
|
page.getByRole('link', { name: 'Attributes' })
|
||||||
).not.toBeAttached()
|
).not.toBeAttached()
|
||||||
@@ -67,6 +64,7 @@ test('should not allow user to view document types', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('should not allow user to view storage paths', async ({ page }) => {
|
test('should not allow user to view storage paths', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('link', { name: 'Attributes' })
|
page.getByRole('link', { name: 'Attributes' })
|
||||||
).not.toBeAttached()
|
).not.toBeAttached()
|
||||||
@@ -77,6 +75,7 @@ test('should not allow user to view storage paths', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('should not allow user to view logs', async ({ page }) => {
|
test('should not allow user to view logs', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(page.getByRole('link', { name: 'Logs' })).not.toBeAttached()
|
await expect(page.getByRole('link', { name: 'Logs' })).not.toBeAttached()
|
||||||
await page.goto('/logs')
|
await page.goto('/logs')
|
||||||
await expect(page.locator('body')).toHaveText(
|
await expect(page.locator('body')).toHaveText(
|
||||||
@@ -85,6 +84,7 @@ test('should not allow user to view logs', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('should not allow user to view tasks', async ({ page }) => {
|
test('should not allow user to view tasks', async ({ page }) => {
|
||||||
|
await page.goto('/dashboard')
|
||||||
await expect(page.getByRole('link', { name: 'Tasks' })).not.toBeAttached()
|
await expect(page.getByRole('link', { name: 'Tasks' })).not.toBeAttached()
|
||||||
await page.goto('/tasks')
|
await page.goto('/tasks')
|
||||||
await expect(page.locator('body')).toHaveText(
|
await expect(page.locator('body')).toHaveText(
|
||||||
|
|||||||
+6
-6
@@ -4389,7 +4389,7 @@
|
|||||||
<source>Create new field</source>
|
<source>Create new field</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-dropdown/custom-fields-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-dropdown/custom-fields-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">19</context>
|
<context context-type="linenumber">20</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6973528734330066202" datatype="html">
|
<trans-unit id="6973528734330066202" datatype="html">
|
||||||
@@ -10334,18 +10334,18 @@
|
|||||||
<context context-type="linenumber">294,295</context>
|
<context context-type="linenumber">294,295</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Preview document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">328</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Preview document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">329</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "paperless-ngx-ui",
|
"name": "paperless-ngx-ui",
|
||||||
"version": "3.4.1",
|
"version": "3.4.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
|
|||||||
+4
-2
@@ -11,12 +11,14 @@
|
|||||||
</div>
|
</div>
|
||||||
@for (field of filteredFields; track field.id) {
|
@for (field of filteredFields; track field.id) {
|
||||||
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addField(field)" #button>
|
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="addField(field)" #button>
|
||||||
<div class="d-flex">{{field.name}} <small class="ms-auto text-muted">{{getDataTypeLabel(field.data_type)}}</small></div>
|
<small class="d-flex">{{field.name}} <small class="ms-auto text-muted">{{getDataTypeLabel(field.data_type)}}</small></small>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@if (!filterText?.length || filteredFields.length === 0) {
|
@if (!filterText?.length || filteredFields.length === 0) {
|
||||||
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="createField(filterText)" [disabled]="!canCreateFields" #button>
|
<button type="button" class="list-group-item list-group-item-action bg-light" (click)="createField(filterText)" [disabled]="!canCreateFields" #button>
|
||||||
<i-bs width=".9em" height=".9em" name="asterisk" class="me-1"></i-bs><ng-container i18n>Create new field</ng-container>
|
<small>
|
||||||
|
<i-bs width=".9em" height=".9em" name="asterisk" class="me-1"></i-bs><ng-container i18n>Create new field</ng-container>
|
||||||
|
</small>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -465,7 +465,7 @@
|
|||||||
@switch (archiveContentRenderType) {
|
@switch (archiveContentRenderType) {
|
||||||
@case (ContentRenderType.PDF) {
|
@case (ContentRenderType.PDF) {
|
||||||
@if (!useNativePdfViewer) {
|
@if (!useNativePdfViewer) {
|
||||||
<div class="preview-sticky pdf-viewer-container" tabindex="-1">
|
<div class="preview-sticky pdf-viewer-container">
|
||||||
<pngx-pdf-viewer
|
<pngx-pdf-viewer
|
||||||
[src]="pdfSource()"
|
[src]="pdfSource()"
|
||||||
[sourceRevision]="previewRevision()"
|
[sourceRevision]="previewRevision()"
|
||||||
@@ -477,7 +477,7 @@
|
|||||||
(loadError)="onError($event)"
|
(loadError)="onError($event)"
|
||||||
(afterLoadComplete)="pdfPreviewLoaded($event)">
|
(afterLoadComplete)="pdfPreviewLoaded($event)">
|
||||||
</pngx-pdf-viewer>
|
</pngx-pdf-viewer>
|
||||||
<div class="preview-controls position-absolute bottom-0 start-50 translate-middle-x z-1 mb-3 d-flex gap-2 p-1 bg-body border rounded shadow">
|
<div class="position-absolute bottom-0 start-50 translate-middle-x z-1 mb-3 d-flex gap-2 p-1 bg-body border rounded shadow">
|
||||||
@if (previewNumPages()) {
|
@if (previewNumPages()) {
|
||||||
<div class="input-group input-group-sm w-auto flex-nowrap">
|
<div class="input-group input-group-sm w-auto flex-nowrap">
|
||||||
<input class="form-control flex-grow-0 w-auto" type="number" min="1" [max]="previewNumPages()" [ngModelOptions]="{standalone: true}" [ngModel]="previewCurrentPage()" (ngModelChange)="previewCurrentPage.set($event)" aria-label="Page" i18n-aria-label />
|
<input class="form-control flex-grow-0 w-auto" type="number" min="1" [max]="previewNumPages()" [ngModelOptions]="{standalone: true}" [ngModel]="previewCurrentPage()" (ngModelChange)="previewCurrentPage.set($event)" aria-label="Page" i18n-aria-label />
|
||||||
|
|||||||
@@ -12,22 +12,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-controls {
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity 0.15s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .preview-controls,
|
|
||||||
&:focus-within .preview-controls {
|
|
||||||
opacity: 1;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-group .dropdown-toggle-split {
|
.btn-group .dropdown-toggle-split {
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,7 @@
|
|||||||
<a class="btn btn-sm btn-outline-secondary" (click)="clickMoreLike.emit()">
|
<a class="btn btn-sm btn-outline-secondary" (click)="clickMoreLike.emit()">
|
||||||
<i-bs name="diagram-3" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>More like this</span>
|
<i-bs name="diagram-3" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>More like this</span>
|
||||||
</a>
|
</a>
|
||||||
<a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary">
|
<a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Document }">
|
||||||
<i-bs name="file-earmark-richtext" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>Open</span>
|
<i-bs name="file-earmark-richtext" class="me-1"></i-bs><span class="d-none d-md-inline" i18n>Open</span>
|
||||||
</a>
|
</a>
|
||||||
<pngx-preview-popup [document]="document()" #popupPreview>
|
<pngx-preview-popup [document]="document()" #popupPreview>
|
||||||
|
|||||||
+2
@@ -10,6 +10,7 @@ import {
|
|||||||
NgbTooltipModule,
|
NgbTooltipModule,
|
||||||
} from '@ng-bootstrap/ng-bootstrap'
|
} from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||||
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||||
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
|
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
|
||||||
@@ -51,6 +52,7 @@ describe('DocumentCardLargeComponent', () => {
|
|||||||
DocumentCardLargeComponent,
|
DocumentCardLargeComponent,
|
||||||
DocumentTitlePipe,
|
DocumentTitlePipe,
|
||||||
CustomDatePipe,
|
CustomDatePipe,
|
||||||
|
IfPermissionsDirective,
|
||||||
SafeUrlPipe,
|
SafeUrlPipe,
|
||||||
IsNumberPipe,
|
IsNumberPipe,
|
||||||
PreviewPopupComponent,
|
PreviewPopupComponent,
|
||||||
|
|||||||
+2
@@ -20,6 +20,7 @@ import {
|
|||||||
Document,
|
Document,
|
||||||
} from 'src/app/data/document'
|
} from 'src/app/data/document'
|
||||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
||||||
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
||||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||||
@@ -50,6 +51,7 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
|
|||||||
CorrespondentNamePipe,
|
CorrespondentNamePipe,
|
||||||
DocumentTypeNamePipe,
|
DocumentTypeNamePipe,
|
||||||
StoragePathNamePipe,
|
StoragePathNamePipe,
|
||||||
|
IfPermissionsDirective,
|
||||||
CustomDatePipe,
|
CustomDatePipe,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
NgbTooltipModule,
|
NgbTooltipModule,
|
||||||
|
|||||||
+1
-1
@@ -144,7 +144,7 @@
|
|||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<div class="btn-group w-100">
|
<div class="btn-group w-100">
|
||||||
@if (document()) {
|
@if (document()) {
|
||||||
<a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary" title="Open" i18n-title>
|
<a routerLink="/documents/{{document().id}}" class="btn btn-sm btn-outline-secondary" title="Open" i18n-title *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Document }" i18n-title>
|
||||||
<i-bs name="file-earmark-richtext"></i-bs>
|
<i-bs name="file-earmark-richtext"></i-bs>
|
||||||
</a>
|
</a>
|
||||||
<pngx-preview-popup [document]="document()" #popupPreview>
|
<pngx-preview-popup [document]="document()" #popupPreview>
|
||||||
|
|||||||
+2
@@ -20,6 +20,7 @@ import {
|
|||||||
Document,
|
Document,
|
||||||
} from 'src/app/data/document'
|
} from 'src/app/data/document'
|
||||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
||||||
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
||||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||||
@@ -50,6 +51,7 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
|
|||||||
CorrespondentNamePipe,
|
CorrespondentNamePipe,
|
||||||
DocumentTypeNamePipe,
|
DocumentTypeNamePipe,
|
||||||
StoragePathNamePipe,
|
StoragePathNamePipe,
|
||||||
|
IfPermissionsDirective,
|
||||||
CustomDatePipe,
|
CustomDatePipe,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
NgbTooltipModule,
|
NgbTooltipModule,
|
||||||
|
|||||||
@@ -208,7 +208,7 @@
|
|||||||
i18n>Correspondent</th>
|
i18n>Correspondent</th>
|
||||||
}
|
}
|
||||||
@if (activeDisplayFields.includes(DisplayField.TITLE)) {
|
@if (activeDisplayFields.includes(DisplayField.TITLE)) {
|
||||||
<th class="cursor-pointer ps-5"
|
<th class="cursor-pointer"
|
||||||
pngxSortable="title"
|
pngxSortable="title"
|
||||||
title="Sort by title" i18n-title
|
title="Sort by title" i18n-title
|
||||||
[currentSortField]="list.sortField"
|
[currentSortField]="list.sortField"
|
||||||
@@ -322,13 +322,13 @@
|
|||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
@if (activeDisplayFields.includes(DisplayField.TITLE) || activeDisplayFields.includes(DisplayField.TAGS)) {
|
@if (activeDisplayFields.includes(DisplayField.TITLE) || activeDisplayFields.includes(DisplayField.TAGS)) {
|
||||||
<td width="30%" class="position-relative" [class.ps-5]="activeDisplayFields.includes(DisplayField.TITLE)">
|
<td width="30%">
|
||||||
@if (activeDisplayFields.includes(DisplayField.TITLE)) {
|
@if (activeDisplayFields.includes(DisplayField.TITLE)) {
|
||||||
<div class="d-inline-block" (mouseleave)="popupPreview.close()">
|
<div class="d-inline-block" (mouseleave)="popupPreview.close()">
|
||||||
<pngx-preview-popup class="position-absolute start-0" [document]="d" linkClasses="btn btn-sm btn-link text-secondary" linkTitle="Preview document" (click)="$event.stopPropagation()" i18n-linkTitle #popupPreview>
|
<a routerLink="/documents/{{d.id}}" title="Edit document" i18n-title style="overflow-wrap: anywhere;">{{d.title | documentTitle}}</a>
|
||||||
|
<pngx-preview-popup [document]="d" linkClasses="btn btn-sm btn-link text-secondary" linkTitle="Preview document" (click)="$event.stopPropagation()" i18n-linkTitle #popupPreview>
|
||||||
<i-bs name="eye"></i-bs>
|
<i-bs name="eye"></i-bs>
|
||||||
</pngx-preview-popup>
|
</pngx-preview-popup>
|
||||||
<a routerLink="/documents/{{d.id}}" title="Edit document" i18n-title style="overflow-wrap: anywhere;">{{d.title | documentTitle}}</a>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (activeDisplayFields.includes(DisplayField.TAGS)) {
|
@if (activeDisplayFields.includes(DisplayField.TAGS)) {
|
||||||
|
|||||||
@@ -87,10 +87,6 @@ $paperless-card-breakpoints: (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.table .ps-5 {
|
|
||||||
padding-left: 2.2rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export interface SystemStatus {
|
|||||||
status: SystemStatusItemStatus
|
status: SystemStatusItemStatus
|
||||||
error?: string
|
error?: string
|
||||||
migration_status: {
|
migration_status: {
|
||||||
latest_migration: string | null
|
latest_migration: string
|
||||||
unapplied_migrations: string[]
|
unapplied_migrations: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.4.1',
|
version: '3.4.0',
|
||||||
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/',
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Wysig dokument</target>
|
<target state="translated">Wysig dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Edit document</target>
|
<target state="needs-translation">Edit document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">تعديل المستند</target>
|
<target state="translated">تعديل المستند</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Рэдагаваць дакумент</target>
|
<target state="translated">Рэдагаваць дакумент</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Сортирай по: <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Сортирай по: <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Визуализация на документа</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Редактиране на документа</target>
|
<target state="translated">Редактиране на документа</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Визуализация на документа</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Ordena per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Ordena per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Previsualitza document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Edita document</target>
|
<target state="translated">Edita document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Previsualitza document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Seřadit podle <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Seřadit podle <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Náhled dokumentu</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Upravit dokument</target>
|
<target state="translated">Upravit dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Náhled dokumentu</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Edit document</target>
|
<target state="needs-translation">Edit document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target>
|
<target state="translated">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Dokumentenvorschau</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Dokument bearbeiten</target>
|
<target state="translated">Dokument bearbeiten</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Dokumentenvorschau</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -4795,7 +4795,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">38</context>
|
<context context-type="linenumber">38</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Datumsmodus</target>
|
<target state="needs-translation">Date mode</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7572800523712857519" datatype="html">
|
<trans-unit id="7572800523712857519" datatype="html">
|
||||||
<source>Fixed date</source>
|
<source>Fixed date</source>
|
||||||
@@ -4807,7 +4807,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">40</context>
|
<context context-type="linenumber">40</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Festes Datum</target>
|
<target state="needs-translation">Fixed date</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4108478337308251505" datatype="html">
|
<trans-unit id="4108478337308251505" datatype="html">
|
||||||
<source>Fixed</source>
|
<source>Fixed</source>
|
||||||
@@ -4815,7 +4815,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">41,42</context>
|
<context context-type="linenumber">41,42</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Fixiert</target>
|
<target state="needs-translation">Fixed</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8283919074858117329" datatype="html">
|
<trans-unit id="8283919074858117329" datatype="html">
|
||||||
<source>Relative date</source>
|
<source>Relative date</source>
|
||||||
@@ -4827,7 +4827,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">44</context>
|
<context context-type="linenumber">44</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Relatives Datum</target>
|
<target state="needs-translation">Relative date</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2731996625798485199" datatype="html">
|
<trans-unit id="2731996625798485199" datatype="html">
|
||||||
<source>Relative</source>
|
<source>Relative</source>
|
||||||
@@ -4835,7 +4835,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">45,46</context>
|
<context context-type="linenumber">45,46</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Relativ</target>
|
<target state="needs-translation">Relative</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6533918067030990396" datatype="html">
|
<trans-unit id="6533918067030990396" datatype="html">
|
||||||
<source>Amount</source>
|
<source>Amount</source>
|
||||||
@@ -4843,7 +4843,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">51</context>
|
<context context-type="linenumber">51</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Anzahl</target>
|
<target state="needs-translation">Amount</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8932917860978648376" datatype="html">
|
<trans-unit id="8932917860978648376" datatype="html">
|
||||||
<source>Unit</source>
|
<source>Unit</source>
|
||||||
@@ -4851,7 +4851,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">56,57</context>
|
<context context-type="linenumber">56,57</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Einheit</target>
|
<target state="needs-translation">Unit</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="9138811584797805840" datatype="html">
|
<trans-unit id="9138811584797805840" datatype="html">
|
||||||
<source>Open date picker</source>
|
<source>Open date picker</source>
|
||||||
@@ -4991,7 +4991,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.html</context>
|
||||||
<context context-type="linenumber">119,120</context>
|
<context context-type="linenumber">119,120</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Operator</target>
|
<target state="needs-translation">Operator</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2328549728463836983" datatype="html">
|
<trans-unit id="2328549728463836983" datatype="html">
|
||||||
<source>Remove query</source>
|
<source>Remove query</source>
|
||||||
@@ -5051,7 +5051,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">330</context>
|
<context context-type="linenumber">330</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">vor Tagen</target>
|
<target state="needs-translation">days ago</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2871318661796659216" datatype="html">
|
<trans-unit id="2871318661796659216" datatype="html">
|
||||||
<source>weeks ago</source>
|
<source>weeks ago</source>
|
||||||
@@ -5059,7 +5059,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">331</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">vor Wochen</target>
|
<target state="needs-translation">weeks ago</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6041340836190906216" datatype="html">
|
<trans-unit id="6041340836190906216" datatype="html">
|
||||||
<source>months ago</source>
|
<source>months ago</source>
|
||||||
@@ -5067,7 +5067,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">332</context>
|
<context context-type="linenumber">332</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">vor Monaten</target>
|
<target state="needs-translation">months ago</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="963494111451627204" datatype="html">
|
<trans-unit id="963494111451627204" datatype="html">
|
||||||
<source>years ago</source>
|
<source>years ago</source>
|
||||||
@@ -5075,7 +5075,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">333</context>
|
<context context-type="linenumber">333</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">vor Jahren</target>
|
<target state="needs-translation">years ago</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5555905617885007774" datatype="html">
|
<trans-unit id="5555905617885007774" datatype="html">
|
||||||
<source>days from now</source>
|
<source>days from now</source>
|
||||||
@@ -5083,7 +5083,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">334</context>
|
<context context-type="linenumber">334</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Tage von heute an</target>
|
<target state="needs-translation">days from now</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4298377021616940216" datatype="html">
|
<trans-unit id="4298377021616940216" datatype="html">
|
||||||
<source>weeks from now</source>
|
<source>weeks from now</source>
|
||||||
@@ -5091,7 +5091,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">335</context>
|
<context context-type="linenumber">335</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Wochen von heute an</target>
|
<target state="needs-translation">weeks from now</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2772874767134148305" datatype="html">
|
<trans-unit id="2772874767134148305" datatype="html">
|
||||||
<source>months from now</source>
|
<source>months from now</source>
|
||||||
@@ -5099,7 +5099,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">336</context>
|
<context context-type="linenumber">336</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Monate von heute an</target>
|
<target state="needs-translation">months from now</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6363533917780225967" datatype="html">
|
<trans-unit id="6363533917780225967" datatype="html">
|
||||||
<source>years from now</source>
|
<source>years from now</source>
|
||||||
@@ -5107,7 +5107,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
<context context-type="sourcefile">src/app/components/common/custom-fields-query-dropdown/custom-fields-query-dropdown.component.ts</context>
|
||||||
<context context-type="linenumber">337</context>
|
<context context-type="linenumber">337</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Jahr von heute an</target>
|
<target state="needs-translation">years from now</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6630533861307510614" datatype="html">
|
<trans-unit id="6630533861307510614" datatype="html">
|
||||||
<source>Clear created relative date</source>
|
<source>Clear created relative date</source>
|
||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="final">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target>
|
<target state="final">Nach <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> sortieren</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html" approved="yes">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="final">Dokumentenvorschau</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
|
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="final">Dokument bearbeiten</target>
|
<target state="final">Dokument bearbeiten</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html" approved="yes">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="final">Dokumentenvorschau</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html" approved="yes">
|
<trans-unit id="4512084577073831437" datatype="html" approved="yes">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Επεξεργασία εγγράφου</target>
|
<target state="translated">Επεξεργασία εγγράφου</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Previsualizar documento</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Editar documento</target>
|
<target state="translated">Editar documento</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Previsualizar documento</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Edit document</target>
|
<target state="needs-translation">Edit document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">سند پیش نمایش</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">سند ویرایش</target>
|
<target state="translated">سند ویرایش</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">سند پیش نمایش</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Esikatsele asiakirja</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Muokkaa asiakirjaa</target>
|
<target state="translated">Muokkaa asiakirjaa</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Esikatsele asiakirja</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -3719,7 +3719,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
||||||
<context context-type="linenumber">163</context>
|
<context context-type="linenumber">163</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Erreur lors de la suppression de l’utilisateur « <x id="PH" equiv-text="user.username"/> ».</target>
|
<target state="translated">Erreur lors de la supression de l’utilisateur « <x id="PH" equiv-text="user.username"/> ».</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5766640174051730159" datatype="html" approved="yes">
|
<trans-unit id="5766640174051730159" datatype="html" approved="yes">
|
||||||
<source>Saved group "<x id="PH" equiv-text="newGroup.name"/>".</source>
|
<source>Saved group "<x id="PH" equiv-text="newGroup.name"/>".</source>
|
||||||
@@ -3767,7 +3767,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
||||||
<context context-type="linenumber">220</context>
|
<context context-type="linenumber">220</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Erreur lors de la suppression du groupe « <x id="PH" equiv-text="group.name"/> ».</target>
|
<target state="translated">Erreur lors de la supression du groupe « <x id="PH" equiv-text="group.name"/> ».</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7931334600001636863" datatype="html" approved="yes">
|
<trans-unit id="7931334600001636863" datatype="html" approved="yes">
|
||||||
<source>by Paperless-ngx</source>
|
<source>by Paperless-ngx</source>
|
||||||
@@ -6935,7 +6935,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html</context>
|
||||||
<context context-type="linenumber">410</context>
|
<context context-type="linenumber">410</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Destinataires du courriel</target>
|
<target state="translated">Destinatires du courriel</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7916910101279824329" datatype="html">
|
<trans-unit id="7916910101279824329" datatype="html">
|
||||||
<source>Attach document</source>
|
<source>Attach document</source>
|
||||||
@@ -10930,7 +10930,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
|
<context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
|
||||||
<context context-type="linenumber">8,9</context>
|
<context context-type="linenumber">8,9</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ document().title | documentTitle }}"/> miniature</target>
|
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ document().title | documentTitle }}"/> mignature</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2784168796433474565" datatype="html" approved="yes">
|
<trans-unit id="2784168796433474565" datatype="html" approved="yes">
|
||||||
<source>Filter by tag</source>
|
<source>Filter by tag</source>
|
||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Trier par <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Trier par <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Prévisualiser le document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
|
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="final">Modifier le document</target>
|
<target state="final">Modifier le document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Prévisualiser le document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">מיון לפי <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">מיון לפי <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">תצוגה מקדימה של המסמך</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">עריכת מסמך</target>
|
<target state="translated">עריכת מסמך</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">תצוגה מקדימה של המסמך</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Edit document</target>
|
<target state="needs-translation">Edit document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Sortiraj po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Sortiraj po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Pregledaj dokument</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Uredi dokument</target>
|
<target state="translated">Uredi dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Pregledaj dokument</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Rendezés <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> szerint</target>
|
<target state="translated">Rendezés <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> szerint</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Dokumentum előnézete</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Dokumentum szerkesztése</target>
|
<target state="translated">Dokumentum szerkesztése</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Dokumentum előnézete</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Urutkan berdasarkan <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Urutkan berdasarkan <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Pratinjau dokumen</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Edit dokumen</target>
|
<target state="translated">Edit dokumen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Pratinjau dokumen</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Ordina per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Ordina per <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Anteprima documento</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Modifica documento</target>
|
<target state="translated">Modifica documento</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Anteprima documento</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> でソート</target>
|
<target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> でソート</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">ドキュメントのプレビュー</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">ドキュメントを編集</target>
|
<target state="translated">ドキュメントを編集</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">ドキュメントのプレビュー</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">문서 미리보기</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">문서 수정</target>
|
<target state="translated">문서 수정</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">문서 미리보기</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Dokument editéieren</target>
|
<target state="translated">Dokument editéieren</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Edit document</target>
|
<target state="needs-translation">Edit document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Rediģēt dokumentu</target>
|
<target state="translated">Rediģēt dokumentu</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
+1504
-1503
File diff suppressed because it is too large.
Load diff
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Edit document</target>
|
<target state="needs-translation">Edit document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Sorteer op <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Sorteer op <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Voorbeeld van document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Document bewerken</target>
|
<target state="translated">Document bewerken</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Voorbeeld van document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Sorter etter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Sorter etter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Forhåndsvis dokument</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Rediger dokument</target>
|
<target state="translated">Rediger dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Forhåndsvis dokument</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Sortuj według <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Sortuj według <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Podgląd dokumentu</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Edytuj dokument</target>
|
<target state="translated">Edytuj dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Podgląd dokumentu</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11398,22 +11398,22 @@ Erro ao enviar documentos por e-mail</target>
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Ordenar por <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Prévisualizar documento</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Editar documento</target>
|
<target state="translated">Editar documento</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Prévisualizar documento</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Editar documento</target>
|
<target state="translated">Editar documento</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Sortează după <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Sortează după <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Previzualizare document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Editează document</target>
|
<target state="translated">Editează document</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Previzualizare document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Сортировать по <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Сортировать по <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Предпросмотр документа</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Изменить документ</target>
|
<target state="translated">Изменить документ</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Предпросмотр документа</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11398,22 +11398,22 @@ zhodujúce sa</target>
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Upraviť dokument</target>
|
<target state="translated">Upraviť dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Razvrsti po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Razvrsti po <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Predogled dokumenta</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Uredi dokument</target>
|
<target state="translated">Uredi dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Predogled dokumenta</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Rendit by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Rendit by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Preview dokument</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Redakto dokument</target>
|
<target state="translated">Redakto dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Preview dokument</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11398,22 +11398,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Složi prema <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Složi prema <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Pregledaj dokument</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Uredi dokument</target>
|
<target state="translated">Uredi dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Pregledaj dokument</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Sortera efter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="translated">Sortera efter <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Förhandsvisa dokument</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Redigera dokument</target>
|
<target state="translated">Redigera dokument</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Förhandsvisa dokument</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="needs-translation">Preview document</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">แก้ไขเอกสาร</target>
|
<target state="translated">แก้ไขเอกสาร</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="needs-translation">Preview document</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11398,22 +11398,22 @@ tüm <x id="CLOSE_EMPHASISED_TEXT" ctype="x-em" equiv-text="</em>"/> krite
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> göre sırala</target>
|
<target state="translated"><x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> göre sırala</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Belgeyi ön izle</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Belgeyi düzenle</target>
|
<target state="translated">Belgeyi düzenle</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Belgeyi ön izle</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
<target state="needs-translation">Sort by <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/></target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">Попередній перегляд документа</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">Редагувати документ</target>
|
<target state="translated">Редагувати документ</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">Попередній перегляд документа</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11459,22 +11459,22 @@
|
|||||||
Sắp xếp theo
|
Sắp xếp theo
|
||||||
</target>
|
</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html" approved="yes">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="final">Xem trước tài liệu</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
|
<trans-unit id="2179847500064178686" datatype="html" approved="yes">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="final">Chỉnh sửa tài liệu</target>
|
<target state="final">Chỉnh sửa tài liệu</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html" approved="yes">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="final">Xem trước tài liệu</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html" approved="yes">
|
<trans-unit id="4512084577073831437" datatype="html" approved="yes">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11396,22 +11396,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">按 <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> 排序</target>
|
<target state="translated">按 <x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/> 排序</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">预览文档</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">编辑文档</target>
|
<target state="translated">编辑文档</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">预览文档</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -11397,22 +11397,22 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">以<x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/>排序</target>
|
<target state="translated">以<x id="INTERPOLATION" equiv-text="{{getDisplayCustomFieldTitle(field_id)}}"/>排序</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3420321797707163677" datatype="html">
|
|
||||||
<source>Preview document</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
|
||||||
<context context-type="linenumber">328</context>
|
|
||||||
</context-group>
|
|
||||||
<target state="translated">預覽文件</target>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2179847500064178686" datatype="html">
|
<trans-unit id="2179847500064178686" datatype="html">
|
||||||
<source>Edit document</source>
|
<source>Edit document</source>
|
||||||
<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>
|
||||||
<context context-type="linenumber">331</context>
|
<context context-type="linenumber">328</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">編輯文件</target>
|
<target state="translated">編輯文件</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="3420321797707163677" datatype="html">
|
||||||
|
<source>Preview document</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
|
||||||
|
<context context-type="linenumber">329</context>
|
||||||
|
</context-group>
|
||||||
|
<target state="translated">預覽文件</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4512084577073831437" datatype="html">
|
<trans-unit id="4512084577073831437" datatype="html">
|
||||||
<source>Reset filters / selection</source>
|
<source>Reset filters / selection</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
@@ -77,6 +77,30 @@ def _clear_django_caches() -> None:
|
|||||||
cache.clear()
|
cache.clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def _keep_connection_open_in_atomic(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
"""Make ``close_old_connections()`` a no-op inside the test's transaction.
|
||||||
|
|
||||||
|
The Celery signal handlers call it, as a worker would between tasks. Tests
|
||||||
|
run inside an open atomic block, where Postgres really closes the
|
||||||
|
connection, taking the test transaction and every later test on the
|
||||||
|
worker with it. SQLite in-memory ignores the close, which hid this.
|
||||||
|
"""
|
||||||
|
from django.db.backends.base.base import BaseDatabaseWrapper
|
||||||
|
|
||||||
|
original = BaseDatabaseWrapper.close_if_unusable_or_obsolete
|
||||||
|
|
||||||
|
def close_unless_atomic(self: BaseDatabaseWrapper) -> None:
|
||||||
|
if not self.in_atomic_block:
|
||||||
|
original(self)
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
BaseDatabaseWrapper,
|
||||||
|
"close_if_unusable_or_obsolete",
|
||||||
|
close_unless_atomic,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def paperless_dirs(
|
def paperless_dirs(
|
||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ from typing import TYPE_CHECKING
|
|||||||
import regex as regex_mod
|
import regex as regex_mod
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from pdf2image import convert_from_path
|
from pdf2image import convert_from_path
|
||||||
|
from pikepdf import Page
|
||||||
|
from pikepdf import PasswordError
|
||||||
|
from pikepdf import Pdf
|
||||||
|
|
||||||
from documents.converters import convert_from_tiff_to_pdf
|
from documents.converters import convert_from_tiff_to_pdf
|
||||||
from documents.data_models import ConsumableDocument
|
from documents.data_models import ConsumableDocument
|
||||||
@@ -31,7 +34,6 @@ from documents.utils import maybe_override_pixel_limit
|
|||||||
from paperless.config import BarcodeConfig
|
from paperless.config import BarcodeConfig
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from pikepdf import Page
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
logger = logging.getLogger("paperless.barcodes")
|
logger = logging.getLogger("paperless.barcodes")
|
||||||
@@ -280,8 +282,6 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
# No op if not a TIFF
|
# No op if not a TIFF
|
||||||
self.convert_from_tiff_to_pdf()
|
self.convert_from_tiff_to_pdf()
|
||||||
|
|
||||||
from pikepdf import PasswordError
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.barcodes = scan_pdf(
|
self.barcodes = scan_pdf(
|
||||||
self.pdf_file,
|
self.pdf_file,
|
||||||
@@ -433,8 +433,6 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
|
|
||||||
document_paths = []
|
document_paths = []
|
||||||
fname: str = self.input_doc.original_file.stem
|
fname: str = self.input_doc.original_file.stem
|
||||||
from pikepdf import Pdf
|
|
||||||
|
|
||||||
with Pdf.open(self.pdf_file) as input_pdf:
|
with Pdf.open(self.pdf_file) as input_pdf:
|
||||||
# Start with an empty document
|
# Start with an empty document
|
||||||
current_document: list[Page] = []
|
current_document: list[Page] = []
|
||||||
@@ -518,8 +516,6 @@ def scan_pdf(pdf_path: Path, settings: BarcodeConfig, work_dir: Path) -> list[Ba
|
|||||||
"""
|
"""
|
||||||
barcodes: list[Barcode] = []
|
barcodes: list[Barcode] = []
|
||||||
|
|
||||||
from pikepdf import Pdf
|
|
||||||
|
|
||||||
with Pdf.open(pdf_path) as pdf:
|
with Pdf.open(pdf_path) as pdf:
|
||||||
num_of_pages = len(pdf.pages)
|
num_of_pages = len(pdf.pages)
|
||||||
logger.debug(f"PDF has {num_of_pages} pages")
|
logger.debug(f"PDF has {num_of_pages} pages")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import img2pdf
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from documents.utils import copy_basic_file_stats
|
from documents.utils import copy_basic_file_stats
|
||||||
@@ -16,8 +17,6 @@ def convert_from_tiff_to_pdf(tiff_path: Path, target_directory: Path) -> Path:
|
|||||||
|
|
||||||
Returns the path of the PDF created.
|
Returns the path of the PDF created.
|
||||||
"""
|
"""
|
||||||
import img2pdf
|
|
||||||
|
|
||||||
# override pixel setting if needed
|
# override pixel setting if needed
|
||||||
maybe_override_pixel_limit()
|
maybe_override_pixel_limit()
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from pathlib import Path
|
|||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from pikepdf import Pdf
|
||||||
|
|
||||||
from documents.consumer import ConsumerError
|
from documents.consumer import ConsumerError
|
||||||
from documents.converters import convert_from_tiff_to_pdf
|
from documents.converters import convert_from_tiff_to_pdf
|
||||||
@@ -84,8 +85,6 @@ class CollatePlugin(NoCleanupPluginMixin, NoSetupPluginMixin, ConsumeTaskPlugin)
|
|||||||
valid_staging_exists = True
|
valid_staging_exists = True
|
||||||
|
|
||||||
if valid_staging_exists:
|
if valid_staging_exists:
|
||||||
from pikepdf import Pdf
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Collate pages from second PDF in reverse order
|
# Collate pages from second PDF in reverse order
|
||||||
with Pdf.open(staging) as pdf1, Pdf.open(pdf_file) as pdf2:
|
with Pdf.open(staging) as pdf1, Pdf.open(pdf_file) as pdf2:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from decimal import InvalidOperation
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import dateparser
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import Case
|
from django.db.models import Case
|
||||||
@@ -349,8 +350,6 @@ class DateQueryField(serializers.DateField):
|
|||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
import dateparser
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
parsed = dateparser.parse(
|
parsed = dateparser.parse(
|
||||||
value,
|
value,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from fnmatch import fnmatch
|
from fnmatch import fnmatch
|
||||||
from fnmatch import translate as fnmatch_translate
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
@@ -548,6 +547,48 @@ def existing_document_matches_workflow(
|
|||||||
return (True, None)
|
return (True, None)
|
||||||
|
|
||||||
|
|
||||||
|
def glob_to_database_regex(pattern: str) -> str:
|
||||||
|
"""
|
||||||
|
Translates an fnmatch style glob into a regular expression which the
|
||||||
|
database can evaluate, matching the whole value.
|
||||||
|
|
||||||
|
fnmatch.translate is not usable here: it emits syntax such as (?s:...),
|
||||||
|
atomic groups and named group backreferences, which PostgreSQL rejects.
|
||||||
|
Only constructs common to Python, PostgreSQL and MariaDB are produced.
|
||||||
|
"""
|
||||||
|
parts: list[str] = []
|
||||||
|
i = 0
|
||||||
|
n = len(pattern)
|
||||||
|
while i < n:
|
||||||
|
char = pattern[i]
|
||||||
|
i += 1
|
||||||
|
if char == "*":
|
||||||
|
parts.append(".*")
|
||||||
|
elif char == "?":
|
||||||
|
parts.append(".")
|
||||||
|
elif char == "[":
|
||||||
|
j = i
|
||||||
|
if j < n and pattern[j] == "!":
|
||||||
|
j += 1
|
||||||
|
if j < n and pattern[j] == "]":
|
||||||
|
j += 1
|
||||||
|
while j < n and pattern[j] != "]":
|
||||||
|
j += 1
|
||||||
|
if j >= n:
|
||||||
|
parts.append(r"\[")
|
||||||
|
else:
|
||||||
|
stuff = pattern[i:j].replace("\\", r"\\").replace("[", r"\[")
|
||||||
|
i = j + 1
|
||||||
|
if stuff.startswith("!"):
|
||||||
|
stuff = "^" + stuff[1:]
|
||||||
|
elif stuff.startswith("^"):
|
||||||
|
stuff = "\\" + stuff
|
||||||
|
parts.append(f"[{stuff}]")
|
||||||
|
else:
|
||||||
|
parts.append(re.escape(char))
|
||||||
|
return "^" + "".join(parts) + "$"
|
||||||
|
|
||||||
|
|
||||||
def prefilter_documents_by_workflowtrigger(
|
def prefilter_documents_by_workflowtrigger(
|
||||||
documents: QuerySet[Document],
|
documents: QuerySet[Document],
|
||||||
trigger: WorkflowTrigger,
|
trigger: WorkflowTrigger,
|
||||||
@@ -628,8 +669,9 @@ def prefilter_documents_by_workflowtrigger(
|
|||||||
documents = documents.annotate(**annotations).filter(custom_field_q)
|
documents = documents.annotate(**annotations).filter(custom_field_q)
|
||||||
|
|
||||||
if trigger.filter_filename:
|
if trigger.filter_filename:
|
||||||
regex = fnmatch_translate(trigger.filter_filename).lstrip("^").rstrip("$")
|
documents = documents.filter(
|
||||||
documents = documents.filter(original_filename__iregex=regex)
|
original_filename__iregex=glob_to_database_regex(trigger.filter_filename),
|
||||||
|
)
|
||||||
|
|
||||||
return documents
|
return documents
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ from __future__ import annotations
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
|
import pikepdf
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
@@ -41,8 +43,6 @@ def rotate_pdf(src: Path, dst: Path, degrees: int) -> None:
|
|||||||
Rotate every page relatively on the opened document, not a rebuild, so Info,
|
Rotate every page relatively on the opened document, not a rebuild, so Info,
|
||||||
XMP and outlines are kept. ``src`` is not modified.
|
XMP and outlines are kept. ``src`` is not modified.
|
||||||
"""
|
"""
|
||||||
import pikepdf
|
|
||||||
|
|
||||||
with pikepdf.open(src) as pdf:
|
with pikepdf.open(src) as pdf:
|
||||||
for page in pdf.pages:
|
for page in pdf.pages:
|
||||||
page.rotate(degrees, relative=True)
|
page.rotate(degrees, relative=True)
|
||||||
@@ -58,8 +58,6 @@ def remove_pages(src: Path, dst: Path, pages: Iterable[int]) -> None:
|
|||||||
Duplicates are ignored. Pages are removed highest first so earlier removals
|
Duplicates are ignored. Pages are removed highest first so earlier removals
|
||||||
never shift the index of later ones.
|
never shift the index of later ones.
|
||||||
"""
|
"""
|
||||||
import pikepdf
|
|
||||||
|
|
||||||
unique = sorted(set(pages))
|
unique = sorted(set(pages))
|
||||||
_require_positive(unique)
|
_require_positive(unique)
|
||||||
with pikepdf.open(src) as pdf:
|
with pikepdf.open(src) as pdf:
|
||||||
@@ -83,8 +81,6 @@ def build_pdfs(
|
|||||||
(Info, XMP, outlines) is not carried over. Returns the written paths in output
|
(Info, XMP, outlines) is not carried over. Returns the written paths in output
|
||||||
order.
|
order.
|
||||||
"""
|
"""
|
||||||
import pikepdf
|
|
||||||
|
|
||||||
for specs, _ in outputs:
|
for specs, _ in outputs:
|
||||||
_require_positive(spec.page for spec in specs)
|
_require_positive(spec.page for spec in specs)
|
||||||
|
|
||||||
@@ -144,8 +140,6 @@ def needs_decrypt(src: Path) -> bool:
|
|||||||
True if ``src`` is encrypted. A PDF that needs a password to open at all
|
True if ``src`` is encrypted. A PDF that needs a password to open at all
|
||||||
counts as encrypted.
|
counts as encrypted.
|
||||||
"""
|
"""
|
||||||
import pikepdf
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with pikepdf.open(src) as pdf:
|
with pikepdf.open(src) as pdf:
|
||||||
return bool(pdf.is_encrypted)
|
return bool(pdf.is_encrypted)
|
||||||
@@ -160,8 +154,6 @@ def decrypt_pdf(src: Path, make_dst: Callable[[], Path], password: str) -> Path:
|
|||||||
``make_dst`` is only called once the password has been accepted, so a wrong
|
``make_dst`` is only called once the password has been accepted, so a wrong
|
||||||
password never leaves a destination behind.
|
password never leaves a destination behind.
|
||||||
"""
|
"""
|
||||||
import pikepdf
|
|
||||||
|
|
||||||
with pikepdf.open(src, password=password) as pdf:
|
with pikepdf.open(src, password=password) as pdf:
|
||||||
pdf.remove_unreferenced_resources()
|
pdf.remove_unreferenced_resources()
|
||||||
dst = make_dst()
|
dst = make_dst()
|
||||||
@@ -178,8 +170,6 @@ class PdfMerger:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
import pikepdf
|
|
||||||
|
|
||||||
self._pdf = pikepdf.new()
|
self._pdf = pikepdf.new()
|
||||||
self._version: str = self._pdf.pdf_version
|
self._version: str = self._pdf.pdf_version
|
||||||
|
|
||||||
@@ -195,8 +185,6 @@ class PdfMerger:
|
|||||||
self._pdf.close()
|
self._pdf.close()
|
||||||
|
|
||||||
def add(self, path: Path) -> None:
|
def add(self, path: Path) -> None:
|
||||||
import pikepdf
|
|
||||||
|
|
||||||
with pikepdf.open(str(path)) as pdf:
|
with pikepdf.open(str(path)) as pdf:
|
||||||
self._version = max(self._version, pdf.pdf_version)
|
self._version = max(self._version, pdf.pdf_version)
|
||||||
self._pdf.pages.extend(pdf.pages)
|
self._pdf.pages.extend(pdf.pages)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ from dataclasses import dataclass
|
|||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import Self
|
from typing import Self
|
||||||
|
|
||||||
|
import dateparser
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -78,8 +80,6 @@ class DateParserPluginBase(ABC):
|
|||||||
|
|
||||||
Uses configuration from `self.config`.
|
Uses configuration from `self.config`.
|
||||||
"""
|
"""
|
||||||
import dateparser
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return dateparser.parse(
|
return dateparser.parse(
|
||||||
date_string,
|
date_string,
|
||||||
|
|||||||
@@ -476,13 +476,13 @@ def update_filename_and_move_files(
|
|||||||
return
|
return
|
||||||
|
|
||||||
with FileLock(settings.MEDIA_LOCK):
|
with FileLock(settings.MEDIA_LOCK):
|
||||||
# If this was waiting for the lock, the filename or archive_filename
|
|
||||||
# of this document may have been updated. This happens if multiple updates
|
|
||||||
# get queued from the UI for the same document
|
|
||||||
# So freshen up the data before doing anything
|
|
||||||
instance.refresh_from_db()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# If this was waiting for the lock, the filename or archive_filename
|
||||||
|
# of this document may have been updated. This happens if multiple updates
|
||||||
|
# get queued from the UI for the same document
|
||||||
|
# So freshen up the data before doing anything
|
||||||
|
instance.refresh_from_db()
|
||||||
|
|
||||||
old_filename = instance.filename
|
old_filename = instance.filename
|
||||||
old_source_path = instance.source_path
|
old_source_path = instance.source_path
|
||||||
move_original = False
|
move_original = False
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ from paperless.logging import consume_task_id
|
|||||||
from paperless.parsers import ParserContext
|
from paperless.parsers import ParserContext
|
||||||
from paperless.parsers.registry import get_parser_registry
|
from paperless.parsers.registry import get_parser_registry
|
||||||
from paperless_ai.exceptions import LLMTimeoutError
|
from paperless_ai.exceptions import LLMTimeoutError
|
||||||
|
from paperless_ai.indexing import llm_index_add_or_update_document
|
||||||
|
from paperless_ai.indexing import llm_index_remove_document
|
||||||
|
from paperless_ai.indexing import update_llm_index
|
||||||
|
|
||||||
if settings.AUDIT_LOG_ENABLED:
|
if settings.AUDIT_LOG_ENABLED:
|
||||||
from auditlog.models import LogEntry
|
from auditlog.models import LogEntry
|
||||||
@@ -336,8 +339,6 @@ def bulk_update_documents(document_ids) -> None:
|
|||||||
|
|
||||||
ai_config = AIConfig()
|
ai_config = AIConfig()
|
||||||
if ai_config.llm_index_enabled:
|
if ai_config.llm_index_enabled:
|
||||||
from paperless_ai.indexing import update_llm_index
|
|
||||||
|
|
||||||
update_llm_index(
|
update_llm_index(
|
||||||
rebuild=False,
|
rebuild=False,
|
||||||
document_ids=document_ids,
|
document_ids=document_ids,
|
||||||
@@ -498,8 +499,6 @@ def update_document_content_maybe_archive_file(
|
|||||||
|
|
||||||
ai_config = AIConfig()
|
ai_config = AIConfig()
|
||||||
if ai_config.llm_index_enabled:
|
if ai_config.llm_index_enabled:
|
||||||
from paperless_ai.indexing import llm_index_add_or_update_document
|
|
||||||
|
|
||||||
llm_index_add_or_update_document(document)
|
llm_index_add_or_update_document(document)
|
||||||
|
|
||||||
clear_document_caches(document.pk)
|
clear_document_caches(document.pk)
|
||||||
@@ -801,15 +800,11 @@ def apply_ai_suggestions(self, action_id: int, document_id: int) -> None:
|
|||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def update_document_in_llm_index(document) -> None:
|
def update_document_in_llm_index(document) -> None:
|
||||||
from paperless_ai.indexing import llm_index_add_or_update_document
|
|
||||||
|
|
||||||
llm_index_add_or_update_document(document)
|
llm_index_add_or_update_document(document)
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def remove_document_from_llm_index(document) -> None:
|
def remove_document_from_llm_index(document) -> None:
|
||||||
from paperless_ai.indexing import llm_index_remove_document
|
|
||||||
|
|
||||||
llm_index_remove_document(document)
|
llm_index_remove_document(document)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ def localize_date(value: date | datetime | str, format: str, locale: str) -> str
|
|||||||
|
|
||||||
def format_datetime(value: str | datetime, format: str) -> str:
|
def format_datetime(value: str | datetime, format: str) -> str:
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
parsed = parse_datetime(value) or parse_date(value)
|
value = parse_date(value)
|
||||||
if parsed is None:
|
|
||||||
raise ValueError(f"Invalid date or datetime string: {value!r}")
|
|
||||||
return parsed.strftime(format=format)
|
|
||||||
return value.strftime(format=format)
|
return value.strftime(format=format)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class TestParseString:
|
|||||||
):
|
):
|
||||||
# We still need to mock dateparser.parse to force the exception
|
# We still need to mock dateparser.parse to force the exception
|
||||||
mocker.patch(
|
mocker.patch(
|
||||||
"dateparser.parse",
|
"documents.plugins.date_parsing.base.dateparser.parse",
|
||||||
side_effect=ValueError(
|
side_effect=ValueError(
|
||||||
"Parsing error: 01/01/2024",
|
"Parsing error: 01/01/2024",
|
||||||
),
|
),
|
||||||
@@ -260,7 +260,7 @@ class TestRegexDateParser:
|
|||||||
parser = RegexDateParserPlugin(base_config)
|
parser = RegexDateParserPlugin(base_config)
|
||||||
|
|
||||||
# Patch the dateparser.parse
|
# Patch the dateparser.parse
|
||||||
target = "dateparser.parse"
|
target = "documents.plugins.date_parsing.base.dateparser.parse"
|
||||||
|
|
||||||
def fake_parse(
|
def fake_parse(
|
||||||
date_string: str,
|
date_string: str,
|
||||||
@@ -335,7 +335,7 @@ class TestRegexDateParser:
|
|||||||
)
|
)
|
||||||
parser = RegexDateParserPlugin(cfg)
|
parser = RegexDateParserPlugin(cfg)
|
||||||
|
|
||||||
target = "dateparser.parse"
|
target = "documents.plugins.date_parsing.base.dateparser.parse"
|
||||||
|
|
||||||
def fake_parse(
|
def fake_parse(
|
||||||
date_string: str,
|
date_string: str,
|
||||||
@@ -400,7 +400,7 @@ class TestRegexDateParser:
|
|||||||
parser = RegexDateParserPlugin(cfg)
|
parser = RegexDateParserPlugin(cfg)
|
||||||
|
|
||||||
# Patch the module's dateparser.parse so we can inspect calls
|
# Patch the module's dateparser.parse so we can inspect calls
|
||||||
target = "dateparser.parse"
|
target = "documents.plugins.date_parsing.base.dateparser.parse"
|
||||||
|
|
||||||
def fake_parse(
|
def fake_parse(
|
||||||
date_string: str,
|
date_string: str,
|
||||||
|
|||||||
@@ -1070,7 +1070,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
with (
|
with (
|
||||||
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
||||||
patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
|
patch("paperless.views.llm_index_exists") as mock_exists,
|
||||||
):
|
):
|
||||||
mock_exists.return_value = False
|
mock_exists.return_value = False
|
||||||
self.client.patch(
|
self.client.patch(
|
||||||
@@ -1095,7 +1095,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
with (
|
with (
|
||||||
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
||||||
patch("paperless_ai.indexing.llm_index_exists", return_value=False),
|
patch("paperless.views.llm_index_exists", return_value=False),
|
||||||
):
|
):
|
||||||
self.client.patch(
|
self.client.patch(
|
||||||
f"{self.ENDPOINT}1/",
|
f"{self.ENDPOINT}1/",
|
||||||
@@ -1115,7 +1115,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
with (
|
with (
|
||||||
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
||||||
patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
|
patch("paperless.views.llm_index_exists") as mock_exists,
|
||||||
):
|
):
|
||||||
mock_exists.return_value = True
|
mock_exists.return_value = True
|
||||||
self.client.patch(
|
self.client.patch(
|
||||||
@@ -1136,7 +1136,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
with (
|
with (
|
||||||
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
||||||
patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
|
patch("paperless.views.llm_index_exists") as mock_exists,
|
||||||
):
|
):
|
||||||
mock_exists.return_value = True
|
mock_exists.return_value = True
|
||||||
self.client.patch(
|
self.client.patch(
|
||||||
@@ -1174,7 +1174,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
with (
|
with (
|
||||||
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
patch("documents.tasks.llmindex_index.apply_async") as mock_update,
|
||||||
patch("paperless_ai.indexing.llm_index_exists") as mock_exists,
|
patch("paperless.views.llm_index_exists") as mock_exists,
|
||||||
):
|
):
|
||||||
mock_exists.return_value = True
|
mock_exists.return_value = True
|
||||||
self.client.patch(
|
self.client.patch(
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class TestChatStreamingViewInputValidation(APITestCase):
|
|||||||
return_value=self._mock_ai_enabled(),
|
return_value=self._mock_ai_enabled(),
|
||||||
),
|
),
|
||||||
mock.patch(
|
mock.patch(
|
||||||
"paperless_ai.chat.stream_chat_with_documents",
|
"documents.views.stream_chat_with_documents",
|
||||||
return_value=iter(chunks),
|
return_value=iter(chunks),
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
@@ -104,7 +104,7 @@ class TestChatStreamingViewUnrestrictedFlag:
|
|||||||
"""
|
"""
|
||||||
mocker.patch("documents.views.AIConfig").return_value.ai_enabled = True
|
mocker.patch("documents.views.AIConfig").return_value.ai_enabled = True
|
||||||
return mocker.patch(
|
return mocker.patch(
|
||||||
"paperless_ai.chat.stream_chat_with_documents",
|
"documents.views.stream_chat_with_documents",
|
||||||
return_value=iter(()),
|
return_value=iter(()),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1062,7 +1062,7 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
"custom_fields": [
|
"custom_fields": [
|
||||||
{
|
{
|
||||||
"field": custom_field_doclink.id,
|
"field": custom_field_doclink.id,
|
||||||
"value": [2, 3, 4],
|
"value": [doc2.id, doc3.id, doc4.id],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -1073,13 +1073,13 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(CustomFieldInstance.objects.count(), 4)
|
self.assertEqual(CustomFieldInstance.objects.count(), 4)
|
||||||
_cf_5 = doc2.custom_fields.first()
|
_cf_5 = doc2.custom_fields.first()
|
||||||
assert _cf_5 is not None
|
assert _cf_5 is not None
|
||||||
self.assertEqual(_cf_5.value, [1])
|
self.assertEqual(_cf_5.value, [doc1.id])
|
||||||
_cf_6 = doc3.custom_fields.first()
|
_cf_6 = doc3.custom_fields.first()
|
||||||
assert _cf_6 is not None
|
assert _cf_6 is not None
|
||||||
self.assertEqual(_cf_6.value, [1])
|
self.assertEqual(_cf_6.value, [doc1.id])
|
||||||
_cf_7 = doc4.custom_fields.first()
|
_cf_7 = doc4.custom_fields.first()
|
||||||
assert _cf_7 is not None
|
assert _cf_7 is not None
|
||||||
self.assertEqual(_cf_7.value, [1])
|
self.assertEqual(_cf_7.value, [doc1.id])
|
||||||
|
|
||||||
# Add links appends if necessary
|
# Add links appends if necessary
|
||||||
resp = self.client.patch(
|
resp = self.client.patch(
|
||||||
@@ -1088,7 +1088,7 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
"custom_fields": [
|
"custom_fields": [
|
||||||
{
|
{
|
||||||
"field": custom_field_doclink.id,
|
"field": custom_field_doclink.id,
|
||||||
"value": [1, 4],
|
"value": [doc1.id, doc4.id],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -1098,7 +1098,7 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
_cf_8 = doc4.custom_fields.first()
|
_cf_8 = doc4.custom_fields.first()
|
||||||
assert _cf_8 is not None
|
assert _cf_8 is not None
|
||||||
self.assertEqual(_cf_8.value, [1, 3])
|
self.assertEqual(_cf_8.value, [doc1.id, doc3.id])
|
||||||
|
|
||||||
# Remove one of the links, removed on other doc
|
# Remove one of the links, removed on other doc
|
||||||
resp = self.client.patch(
|
resp = self.client.patch(
|
||||||
@@ -1107,7 +1107,7 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
"custom_fields": [
|
"custom_fields": [
|
||||||
{
|
{
|
||||||
"field": custom_field_doclink.id,
|
"field": custom_field_doclink.id,
|
||||||
"value": [2, 3],
|
"value": [doc2.id, doc3.id],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -1117,13 +1117,13 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
_cf_9 = doc2.custom_fields.first()
|
_cf_9 = doc2.custom_fields.first()
|
||||||
assert _cf_9 is not None
|
assert _cf_9 is not None
|
||||||
self.assertEqual(_cf_9.value, [1])
|
self.assertEqual(_cf_9.value, [doc1.id])
|
||||||
_cf_10 = doc3.custom_fields.first()
|
_cf_10 = doc3.custom_fields.first()
|
||||||
assert _cf_10 is not None
|
assert _cf_10 is not None
|
||||||
self.assertEqual(_cf_10.value, [1, 4])
|
self.assertEqual(_cf_10.value, [doc1.id, doc4.id])
|
||||||
_cf_11 = doc4.custom_fields.first()
|
_cf_11 = doc4.custom_fields.first()
|
||||||
assert _cf_11 is not None
|
assert _cf_11 is not None
|
||||||
self.assertEqual(_cf_11.value, [3])
|
self.assertEqual(_cf_11.value, [doc3.id])
|
||||||
|
|
||||||
# Removes the field entirely
|
# Removes the field entirely
|
||||||
resp = self.client.patch(
|
resp = self.client.patch(
|
||||||
@@ -1140,10 +1140,10 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(_cf_12.value, [])
|
self.assertEqual(_cf_12.value, [])
|
||||||
_cf_13 = doc3.custom_fields.first()
|
_cf_13 = doc3.custom_fields.first()
|
||||||
assert _cf_13 is not None
|
assert _cf_13 is not None
|
||||||
self.assertEqual(_cf_13.value, [4])
|
self.assertEqual(_cf_13.value, [doc4.id])
|
||||||
_cf_14 = doc4.custom_fields.first()
|
_cf_14 = doc4.custom_fields.first()
|
||||||
assert _cf_14 is not None
|
assert _cf_14 is not None
|
||||||
self.assertEqual(_cf_14.value, [3])
|
self.assertEqual(_cf_14.value, [doc3.id])
|
||||||
|
|
||||||
# If field exists on target doc but value is None
|
# If field exists on target doc but value is None
|
||||||
doc5 = Document.objects.create(
|
doc5 = Document.objects.create(
|
||||||
@@ -1170,7 +1170,7 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
_cf_15 = doc5.custom_fields.first()
|
_cf_15 = doc5.custom_fields.first()
|
||||||
assert _cf_15 is not None
|
assert _cf_15 is not None
|
||||||
self.assertEqual(_cf_15.value, [1])
|
self.assertEqual(_cf_15.value, [doc1.id])
|
||||||
|
|
||||||
def test_documentlink_patch_requires_change_permission_on_target_documents(
|
def test_documentlink_patch_requires_change_permission_on_target_documents(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -1110,7 +1110,7 @@ class TestVersionActionPermissions(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
with (
|
with (
|
||||||
mock.patch("documents.views.AIConfig") as ai_config,
|
mock.patch("documents.views.AIConfig") as ai_config,
|
||||||
mock.patch("paperless_ai.chat.stream_chat_with_documents") as chat,
|
mock.patch("documents.views.stream_chat_with_documents") as chat,
|
||||||
):
|
):
|
||||||
ai_config.return_value.ai_enabled = True
|
ai_config.return_value.ai_enabled = True
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
|
|||||||
@@ -2686,7 +2686,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
|
|||||||
response = self.client.get("/api/documents/34676/suggestions/")
|
response = self.client.get("/api/documents/34676/suggestions/")
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
@mock.patch("paperless_ai.ai_classifier.get_ai_document_classification")
|
@mock.patch("documents.views.get_ai_document_classification")
|
||||||
@override_settings(AI_ENABLED=True)
|
@override_settings(AI_ENABLED=True)
|
||||||
def test_suggestions_still_uses_classifier_when_ai_enabled(
|
def test_suggestions_still_uses_classifier_when_ai_enabled(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from unittest.mock import patch
|
|||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
import time_machine
|
import time_machine
|
||||||
|
from django.db import connection
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
@@ -20,6 +21,13 @@ from paperless_testing.dirs import DirectoriesMixin
|
|||||||
from paperless_testing.factories import UserFactory
|
from paperless_testing.factories import UserFactory
|
||||||
|
|
||||||
|
|
||||||
|
def _exact_equal(value: str | None, expected: str) -> bool:
|
||||||
|
"""`exact` follows the column collation, which is case insensitive on MariaDB."""
|
||||||
|
if connection.vendor == "mysql" and value is not None:
|
||||||
|
return value.casefold() == expected.casefold()
|
||||||
|
return value == expected
|
||||||
|
|
||||||
|
|
||||||
class DocumentWrapper:
|
class DocumentWrapper:
|
||||||
"""
|
"""
|
||||||
Allows Pythonic access to the custom fields associated with the wrapped document.
|
Allows Pythonic access to the custom fields associated with the wrapped document.
|
||||||
@@ -287,7 +295,8 @@ class TestCustomFieldsSearch(DirectoriesMixin, APITestCase):
|
|||||||
self._assert_query_match_predicate(
|
self._assert_query_match_predicate(
|
||||||
["string_field", "exact", "paperless"],
|
["string_field", "exact", "paperless"],
|
||||||
lambda document: (
|
lambda document: (
|
||||||
"string_field" in document and document["string_field"] == "paperless"
|
"string_field" in document
|
||||||
|
and _exact_equal(document["string_field"], "paperless")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -296,7 +305,10 @@ class TestCustomFieldsSearch(DirectoriesMixin, APITestCase):
|
|||||||
["string_field", "in", ["paperless", "Paperless"]],
|
["string_field", "in", ["paperless", "Paperless"]],
|
||||||
lambda document: (
|
lambda document: (
|
||||||
"string_field" in document
|
"string_field" in document
|
||||||
and document["string_field"] in ("paperless", "Paperless")
|
and any(
|
||||||
|
_exact_equal(document["string_field"], expected)
|
||||||
|
for expected in ("paperless", "Paperless")
|
||||||
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -628,22 +640,23 @@ class TestCustomFieldsSearch(DirectoriesMixin, APITestCase):
|
|||||||
# Subset check (document link field only) #
|
# Subset check (document link field only) #
|
||||||
# ==========================================================#
|
# ==========================================================#
|
||||||
def test_document_link_contains(self) -> None:
|
def test_document_link_contains(self) -> None:
|
||||||
|
linked = {self.documents[1].id, self.documents[2].id}
|
||||||
# Document link field "contains" performs a subset check.
|
# Document link field "contains" performs a subset check.
|
||||||
self._assert_query_match_predicate(
|
self._assert_query_match_predicate(
|
||||||
["documentlink_field", "contains", [1, 2]],
|
["documentlink_field", "contains", sorted(linked)],
|
||||||
lambda document: (
|
lambda document: (
|
||||||
"documentlink_field" in document
|
"documentlink_field" in document
|
||||||
and document["documentlink_field"] is not None
|
and document["documentlink_field"] is not None
|
||||||
and set(document["documentlink_field"]) >= {1, 2}
|
and set(document["documentlink_field"]) >= linked
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
# The order of IDs don't matter - this is the same as above.
|
# The order of IDs don't matter - this is the same as above.
|
||||||
self._assert_query_match_predicate(
|
self._assert_query_match_predicate(
|
||||||
["documentlink_field", "contains", [2, 1]],
|
["documentlink_field", "contains", sorted(linked, reverse=True)],
|
||||||
lambda document: (
|
lambda document: (
|
||||||
"documentlink_field" in document
|
"documentlink_field" in document
|
||||||
and document["documentlink_field"] is not None
|
and document["documentlink_field"] is not None
|
||||||
and set(document["documentlink_field"]) >= {1, 2}
|
and set(document["documentlink_field"]) >= linked
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -760,7 +773,7 @@ class TestCustomFieldsSearch(DirectoriesMixin, APITestCase):
|
|||||||
lambda document: (
|
lambda document: (
|
||||||
not (
|
not (
|
||||||
"string_field" in document
|
"string_field" in document
|
||||||
and document["string_field"] == "paperless"
|
and _exact_equal(document["string_field"], "paperless")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -308,32 +308,3 @@ class TestBulkDownloadSchema:
|
|||||||
def test_bulk_download_response_403(self, api_schema: SchemaGenerator) -> None:
|
def test_bulk_download_response_403(self, api_schema: SchemaGenerator) -> None:
|
||||||
op = api_schema["paths"]["/api/documents/bulk_download/"]["post"]
|
op = api_schema["paths"]["/api/documents/bulk_download/"]["post"]
|
||||||
assert "403" in op["responses"]
|
assert "403" in op["responses"]
|
||||||
|
|
||||||
|
|
||||||
class TestDocumentListObjectFilterSchema:
|
|
||||||
"""documents_list: comma-separated ObjectFilter params must be typed as integer arrays."""
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"param_name",
|
|
||||||
[
|
|
||||||
"tags__id__all",
|
|
||||||
"tags__id__none",
|
|
||||||
"tags__id__in",
|
|
||||||
"correspondent__id__none",
|
|
||||||
"document_type__id__none",
|
|
||||||
"storage_path__id__none",
|
|
||||||
"owner__id__none",
|
|
||||||
"custom_fields__id__all",
|
|
||||||
"custom_fields__id__none",
|
|
||||||
"custom_fields__id__in",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_object_filter_param_is_integer_array(
|
|
||||||
self,
|
|
||||||
api_schema: SchemaGenerator,
|
|
||||||
param_name: str,
|
|
||||||
) -> None:
|
|
||||||
params = api_schema["paths"]["/api/documents/"]["get"]["parameters"]
|
|
||||||
param = next(p for p in params if p["name"] == param_name)
|
|
||||||
assert param["schema"] == {"type": "array", "items": {"type": "integer"}}
|
|
||||||
assert param["explode"] is False
|
|
||||||
@@ -944,7 +944,7 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
results = response.data["results"]
|
results = response.data["results"]
|
||||||
self.assertEqual({r["id"] for r in results}, {1, 2})
|
self.assertEqual({r["id"] for r in results}, {d1.id, d2.id})
|
||||||
|
|
||||||
@mock.patch("documents.search._backend.parse_user_query")
|
@mock.patch("documents.search._backend.parse_user_query")
|
||||||
def test_search_parser_bug_surfaces_as_500_not_400(self, m) -> None:
|
def test_search_parser_bug_surfaces_as_500_not_400(self, m) -> None:
|
||||||
@@ -1801,6 +1801,7 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
|
|||||||
def test_search_sorting(self) -> None:
|
def test_search_sorting(self) -> None:
|
||||||
u1 = UserFactory(username="user1")
|
u1 = UserFactory(username="user1")
|
||||||
u2 = UserFactory(username="user2")
|
u2 = UserFactory(username="user2")
|
||||||
|
u3 = UserFactory(username="user3")
|
||||||
c1 = Correspondent.objects.create(name="corres Ax")
|
c1 = Correspondent.objects.create(name="corres Ax")
|
||||||
c2 = Correspondent.objects.create(name="corres Cx")
|
c2 = Correspondent.objects.create(name="corres Cx")
|
||||||
c3 = Correspondent.objects.create(name="corres Bx")
|
c3 = Correspondent.objects.create(name="corres Bx")
|
||||||
@@ -1826,6 +1827,7 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
|
|||||||
content="test",
|
content="test",
|
||||||
archive_serial_number=1,
|
archive_serial_number=1,
|
||||||
title="1",
|
title="1",
|
||||||
|
owner=u3,
|
||||||
)
|
)
|
||||||
Note.objects.create(
|
Note.objects.create(
|
||||||
note="This is a note.",
|
note="This is a note.",
|
||||||
@@ -1878,14 +1880,14 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
|
|||||||
search_query("&ordering=-num_notes"),
|
search_query("&ordering=-num_notes"),
|
||||||
[d1.id, d3.id, d2.id],
|
[d1.id, d3.id, d2.id],
|
||||||
)
|
)
|
||||||
# owner sort: ORM orders by owner_id (integer); NULLs first in SQLite ASC
|
# owner sort: ORM orders by owner_id (integer)
|
||||||
self.assertListEqual(
|
self.assertListEqual(
|
||||||
search_query("&ordering=owner"),
|
search_query("&ordering=owner"),
|
||||||
[d3.id, d1.id, d2.id],
|
[d1.id, d2.id, d3.id],
|
||||||
)
|
)
|
||||||
self.assertListEqual(
|
self.assertListEqual(
|
||||||
search_query("&ordering=-owner"),
|
search_query("&ordering=-owner"),
|
||||||
[d2.id, d1.id, d3.id],
|
[d3.id, d2.id, d1.id],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_search_ordering_by_score(self) -> None:
|
def test_search_ordering_by_score(self) -> None:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from datetime import timedelta
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.db import connection
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
@@ -68,7 +69,7 @@ class TestSystemStatus(APITestCase):
|
|||||||
self.assertEqual(response.data["install_type"], "bare-metal")
|
self.assertEqual(response.data["install_type"], "bare-metal")
|
||||||
self.assertIsNotNone(response.data["storage"]["total"])
|
self.assertIsNotNone(response.data["storage"]["total"])
|
||||||
self.assertIsNotNone(response.data["storage"]["available"])
|
self.assertIsNotNone(response.data["storage"]["available"])
|
||||||
self.assertEqual(response.data["database"]["type"], "sqlite")
|
self.assertEqual(response.data["database"]["type"], connection.vendor)
|
||||||
self.assertIsNotNone(response.data["database"]["url"])
|
self.assertIsNotNone(response.data["database"]["url"])
|
||||||
self.assertEqual(response.data["database"]["status"], "OK")
|
self.assertEqual(response.data["database"]["status"], "OK")
|
||||||
self.assertIsNone(response.data["database"]["error"])
|
self.assertIsNone(response.data["database"]["error"])
|
||||||
@@ -539,50 +540,3 @@ class TestSystemStatus(APITestCase):
|
|||||||
self.assertEqual(response.data["tasks"]["summary"]["success_count"], 1)
|
self.assertEqual(response.data["tasks"]["summary"]["success_count"], 1)
|
||||||
self.assertEqual(response.data["tasks"]["summary"]["failure_count"], 1)
|
self.assertEqual(response.data["tasks"]["summary"]["failure_count"], 1)
|
||||||
self.assertEqual(response.data["tasks"]["summary"]["pending_count"], 1)
|
self.assertEqual(response.data["tasks"]["summary"]["pending_count"], 1)
|
||||||
|
|
||||||
def test_system_status_reports_database_error(self) -> None:
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- Reading the migration state fails
|
|
||||||
WHEN:
|
|
||||||
- The system status is requested
|
|
||||||
THEN:
|
|
||||||
- The response reports the database error rather than a server error
|
|
||||||
"""
|
|
||||||
self.client.force_login(self.user)
|
|
||||||
with mock.patch(
|
|
||||||
"documents.views.MigrationLoader",
|
|
||||||
side_effect=Exception("database is down"),
|
|
||||||
):
|
|
||||||
response = self.client.get(self.ENDPOINT)
|
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
database = response.data["database"]
|
|
||||||
self.assertEqual(database["status"], "ERROR")
|
|
||||||
self.assertIsNotNone(database["error"])
|
|
||||||
self.assertEqual(
|
|
||||||
database["migration_status"],
|
|
||||||
{"latest_migration": None, "unapplied_migrations": []},
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_system_status_migration_query_error(self) -> None:
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- The migration graph loads but reading the applied migrations fails
|
|
||||||
WHEN:
|
|
||||||
- The system status is requested
|
|
||||||
THEN:
|
|
||||||
- No migrations are reported as unapplied, since the state is unknown
|
|
||||||
"""
|
|
||||||
self.client.force_login(self.user)
|
|
||||||
with mock.patch("documents.views.MigrationRecorder") as recorder:
|
|
||||||
recorder.Migration.objects.all.side_effect = Exception("query failed")
|
|
||||||
response = self.client.get(self.ENDPOINT)
|
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
database = response.data["database"]
|
|
||||||
self.assertEqual(database["status"], "ERROR")
|
|
||||||
self.assertEqual(
|
|
||||||
database["migration_status"],
|
|
||||||
{"latest_migration": None, "unapplied_migrations": []},
|
|
||||||
)
|
|
||||||
@@ -1031,9 +1031,7 @@ class TestPDFActions(DirectoriesMixin, TestCase):
|
|||||||
with self.assertLogs("paperless.bulk_edit", level="ERROR") as cm:
|
with self.assertLogs("paperless.bulk_edit", level="ERROR") as cm:
|
||||||
bulk_edit.merge(doc_ids)
|
bulk_edit.merge(doc_ids)
|
||||||
error_str = cm.output[0]
|
error_str = cm.output[0]
|
||||||
expected_str = (
|
expected_str = f"Error merging document {self.doc2.id}, it will not be included in the merge"
|
||||||
"Error merging document 2, it will not be included in the merge"
|
|
||||||
)
|
|
||||||
self.assertIn(expected_str, error_str)
|
self.assertIn(expected_str, error_str)
|
||||||
|
|
||||||
mock_consume_file.assert_not_called()
|
mock_consume_file.assert_not_called()
|
||||||
@@ -1193,7 +1191,7 @@ class TestPDFActions(DirectoriesMixin, TestCase):
|
|||||||
with self.assertLogs("paperless.bulk_edit", level="ERROR") as cm:
|
with self.assertLogs("paperless.bulk_edit", level="ERROR") as cm:
|
||||||
bulk_edit.split(doc_ids, pages)
|
bulk_edit.split(doc_ids, pages)
|
||||||
error_str = cm.output[0]
|
error_str = cm.output[0]
|
||||||
expected_str = "Error splitting document 2"
|
expected_str = f"Error splitting document {self.doc2.id}"
|
||||||
self.assertIn(expected_str, error_str)
|
self.assertIn(expected_str, error_str)
|
||||||
|
|
||||||
mock_consume_file.assert_not_called()
|
mock_consume_file.assert_not_called()
|
||||||
|
|||||||
@@ -248,8 +248,8 @@ class TestConsumer(
|
|||||||
)
|
)
|
||||||
self.assertIsNone(document.correspondent)
|
self.assertIsNone(document.correspondent)
|
||||||
self.assertIsNone(document.document_type)
|
self.assertIsNone(document.document_type)
|
||||||
self.assertEqual(document.filename, "0000001.pdf")
|
self.assertEqual(document.filename, f"{document.pk:07}.pdf")
|
||||||
self.assertEqual(document.archive_filename, "0000001.pdf")
|
self.assertEqual(document.archive_filename, f"{document.pk:07}.pdf")
|
||||||
|
|
||||||
self.assertIsFile(document.source_path)
|
self.assertIsFile(document.source_path)
|
||||||
|
|
||||||
@@ -1127,17 +1127,17 @@ class TestConsumer(
|
|||||||
with self.get_consumer(settings.CONSUMPTION_DIR / "simple.png") as consumer:
|
with self.get_consumer(settings.CONSUMPTION_DIR / "simple.png") as consumer:
|
||||||
consumer.run()
|
consumer.run()
|
||||||
|
|
||||||
doc1 = Document.objects.filter(pk=1).first()
|
doc1 = Document.objects.latest("pk")
|
||||||
|
|
||||||
with self.get_consumer(settings.CONSUMPTION_DIR / "simple.pdf") as consumer:
|
with self.get_consumer(settings.CONSUMPTION_DIR / "simple.pdf") as consumer:
|
||||||
consumer.run()
|
consumer.run()
|
||||||
|
|
||||||
doc2 = Document.objects.filter(pk=2).first()
|
doc2 = Document.objects.latest("pk")
|
||||||
|
|
||||||
with self.get_consumer(settings.CONSUMPTION_DIR / "simple.png.pdf") as consumer:
|
with self.get_consumer(settings.CONSUMPTION_DIR / "simple.png.pdf") as consumer:
|
||||||
consumer.run()
|
consumer.run()
|
||||||
|
|
||||||
doc3 = Document.objects.filter(pk=3).first()
|
doc3 = Document.objects.latest("pk")
|
||||||
|
|
||||||
self.assertEqual(doc1.filename, "simple.png")
|
self.assertEqual(doc1.filename, "simple.png")
|
||||||
self.assertEqual(doc1.archive_filename, "simple.pdf")
|
self.assertEqual(doc1.archive_filename, "simple.pdf")
|
||||||
|
|||||||
@@ -242,9 +242,7 @@ class TestDocumentListEffectiveContentAnnotation:
|
|||||||
# Only the list query itself reads a content column: no extra query
|
# Only the list query itself reads a content column: no extra query
|
||||||
# for the skipped prefetch, none for a per-instance fallback
|
# for the skipped prefetch, none for a per-instance fallback
|
||||||
content_queries = [
|
content_queries = [
|
||||||
query
|
query for query in ctx.captured_queries if _content_column() in query["sql"]
|
||||||
for query in ctx.captured_queries
|
|
||||||
if '"documents_document"."content"' in query["sql"]
|
|
||||||
]
|
]
|
||||||
assert len(content_queries) == 1
|
assert len(content_queries) == 1
|
||||||
|
|
||||||
@@ -365,6 +363,11 @@ def _get_document_queries(
|
|||||||
return [q for q in ctx.captured_queries if '"django_content_type"' not in q["sql"]]
|
return [q for q in ctx.captured_queries if '"django_content_type"' not in q["sql"]]
|
||||||
|
|
||||||
|
|
||||||
|
def _content_column() -> str:
|
||||||
|
quote = connection.ops.quote_name
|
||||||
|
return f"{quote('documents_document')}.{quote('content')}"
|
||||||
|
|
||||||
|
|
||||||
def _get_effective_content_fallback_queries(
|
def _get_effective_content_fallback_queries(
|
||||||
ctx: CaptureQueriesContext,
|
ctx: CaptureQueriesContext,
|
||||||
) -> list[dict[str, str]]:
|
) -> list[dict[str, str]]:
|
||||||
@@ -379,7 +382,7 @@ def _get_effective_content_fallback_queries(
|
|||||||
return [
|
return [
|
||||||
q
|
q
|
||||||
for q in ctx.captured_queries
|
for q in ctx.captured_queries
|
||||||
if q["sql"].startswith('SELECT "documents_document"."content" FROM')
|
if q["sql"].startswith(f"SELECT {_content_column()} FROM")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ from documents.serialisers import DocumentSerializer
|
|||||||
from documents.tasks import empty_trash
|
from documents.tasks import empty_trash
|
||||||
from paperless_testing.assertions import FileSystemAssertsMixin
|
from paperless_testing.assertions import FileSystemAssertsMixin
|
||||||
from paperless_testing.dirs import DirectoriesMixin
|
from paperless_testing.dirs import DirectoriesMixin
|
||||||
from paperless_testing.dirs import PaperlessDirs
|
|
||||||
from paperless_testing.factories import DocumentFactory
|
from paperless_testing.factories import DocumentFactory
|
||||||
from paperless_testing.factories import UserFactory
|
from paperless_testing.factories import UserFactory
|
||||||
|
|
||||||
@@ -761,6 +760,9 @@ class TestFileHandlingWithArchive(DirectoriesMixin, FileSystemAssertsMixin, Test
|
|||||||
archive_checksum="B",
|
archive_checksum="B",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Without a format the files are renamed to match the primary key
|
||||||
|
original = doc.source_path
|
||||||
|
archive = doc.archive_path
|
||||||
self.assertIsFile(original)
|
self.assertIsFile(original)
|
||||||
self.assertIsFile(archive)
|
self.assertIsFile(archive)
|
||||||
self.assertIsFile(doc.source_path)
|
self.assertIsFile(doc.source_path)
|
||||||
@@ -979,6 +981,9 @@ class TestFileHandlingWithArchive(DirectoriesMixin, FileSystemAssertsMixin, Test
|
|||||||
archive_filename="0000001.pdf",
|
archive_filename="0000001.pdf",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Without a format the files are renamed to match the primary key
|
||||||
|
original = doc.source_path
|
||||||
|
archive = doc.archive_path
|
||||||
self.assertIsFile(original)
|
self.assertIsFile(original)
|
||||||
self.assertIsFile(archive)
|
self.assertIsFile(archive)
|
||||||
self.assertIsFile(doc.source_path)
|
self.assertIsFile(doc.source_path)
|
||||||
@@ -2135,28 +2140,3 @@ class TestPathDateLocalization:
|
|||||||
with override_settings(FILENAME_FORMAT=filename_format):
|
with override_settings(FILENAME_FORMAT=filename_format):
|
||||||
filename = generate_filename(document)
|
filename = generate_filename(document)
|
||||||
assert filename == Path(expected_filename)
|
assert filename == Path(expected_filename)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_refresh_failure_surfaces_database_error(
|
|
||||||
paperless_dirs: PaperlessDirs,
|
|
||||||
) -> None:
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- A document with a stored filename
|
|
||||||
WHEN:
|
|
||||||
- Saving it triggers a filename update and refreshing it from the database fails
|
|
||||||
THEN:
|
|
||||||
- The database error is raised, not an unbound variable error from the rollback
|
|
||||||
"""
|
|
||||||
document = DocumentFactory(filename="some.pdf")
|
|
||||||
|
|
||||||
with (
|
|
||||||
mock.patch.object(
|
|
||||||
Document,
|
|
||||||
"refresh_from_db",
|
|
||||||
side_effect=DatabaseError("database is locked"),
|
|
||||||
),
|
|
||||||
pytest.raises(DatabaseError, match="database is locked"),
|
|
||||||
):
|
|
||||||
document.save()
|
|
||||||
@@ -4,7 +4,6 @@ from typing import Literal
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from documents.templating.filters import format_datetime
|
|
||||||
from documents.templating.filters import localize_date
|
from documents.templating.filters import localize_date
|
||||||
|
|
||||||
|
|
||||||
@@ -295,23 +294,3 @@ class TestDateLocalization:
|
|||||||
Tests `localize_date` with `date` string across different locales and formats.
|
Tests `localize_date` with `date` string across different locales and formats.
|
||||||
"""
|
"""
|
||||||
assert localize_date(value, format_style, locale_str) == expected_output
|
assert localize_date(value, format_style, locale_str) == expected_output
|
||||||
|
|
||||||
|
|
||||||
class TestFormatDatetime:
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
("value", "expected"),
|
|
||||||
[
|
|
||||||
pytest.param("2026-09-21", "2026-09-21 00:00", id="date"),
|
|
||||||
pytest.param(
|
|
||||||
"2026-09-21T13:45:00+00:00",
|
|
||||||
"2026-09-21 13:45",
|
|
||||||
id="datetime",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_parses_iso_strings(self, value: str, expected: str) -> None:
|
|
||||||
assert format_datetime(value, "%Y-%m-%d %H:%M") == expected
|
|
||||||
|
|
||||||
def test_rejects_unparseable_string(self) -> None:
|
|
||||||
with pytest.raises(ValueError, match="not a date"):
|
|
||||||
format_datetime("not a date", "%Y")
|
|
||||||
@@ -151,6 +151,20 @@ class TestExportImport(
|
|||||||
|
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
|
def _install_sample_files(self) -> None:
|
||||||
|
documents_dir = Path(self.dirs.media_dir) / "documents"
|
||||||
|
shutil.rmtree(documents_dir)
|
||||||
|
install_document_samples(documents_dir)
|
||||||
|
# Thumbnails are located by primary key, which the database sequence
|
||||||
|
# does not reset between tests on PostgreSQL
|
||||||
|
for number, document in enumerate(
|
||||||
|
(self.d1, self.d2, self.d3, self.d4),
|
||||||
|
start=1,
|
||||||
|
):
|
||||||
|
source = documents_dir / "thumbnails" / f"{number:07}.webp"
|
||||||
|
if source != document.thumbnail_path:
|
||||||
|
shutil.copy(source, document.thumbnail_path)
|
||||||
|
|
||||||
def _get_document_from_manifest(self, manifest, id):
|
def _get_document_from_manifest(self, manifest, id):
|
||||||
f = list(
|
f = list(
|
||||||
filter(
|
filter(
|
||||||
@@ -204,8 +218,7 @@ class TestExportImport(
|
|||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
def test_exporter(self, *, use_filename_format=False) -> None:
|
def test_exporter(self, *, use_filename_format=False) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
num_permission_objects = Permission.objects.count()
|
num_permission_objects = Permission.objects.count()
|
||||||
|
|
||||||
@@ -308,8 +321,7 @@ class TestExportImport(
|
|||||||
self.assertEqual(messages.total_issue_count, 0)
|
self.assertEqual(messages.total_issue_count, 0)
|
||||||
|
|
||||||
def test_exporter_with_filename_format(self) -> None:
|
def test_exporter_with_filename_format(self) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
with override_settings(
|
with override_settings(
|
||||||
FILENAME_FORMAT="{created_year}/{correspondent}/{title}",
|
FILENAME_FORMAT="{created_year}/{correspondent}/{title}",
|
||||||
@@ -317,8 +329,7 @@ class TestExportImport(
|
|||||||
self.test_exporter(use_filename_format=True)
|
self.test_exporter(use_filename_format=True)
|
||||||
|
|
||||||
def test_exporter_includes_share_links_and_bundles(self) -> None:
|
def test_exporter_includes_share_links_and_bundles(self) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
share_link = ShareLink.objects.create(
|
share_link = ShareLink.objects.create(
|
||||||
slug="share-link-slug",
|
slug="share-link-slug",
|
||||||
@@ -416,8 +427,7 @@ class TestExportImport(
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_update_export_changed_time(self) -> None:
|
def test_update_export_changed_time(self) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
self._do_export()
|
self._do_export()
|
||||||
self.assertIsFile(self.target / "manifest.json")
|
self.assertIsFile(self.target / "manifest.json")
|
||||||
@@ -452,8 +462,7 @@ class TestExportImport(
|
|||||||
self.assertEqual(st_mtime_3, st_mtime_4)
|
self.assertEqual(st_mtime_3, st_mtime_4)
|
||||||
|
|
||||||
def test_update_export_changed_checksum(self) -> None:
|
def test_update_export_changed_checksum(self) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
self._do_export()
|
self._do_export()
|
||||||
|
|
||||||
@@ -479,8 +488,7 @@ class TestExportImport(
|
|||||||
self.assertIsFile(self.target / "manifest.json")
|
self.assertIsFile(self.target / "manifest.json")
|
||||||
|
|
||||||
def test_update_export_deleted_document(self) -> None:
|
def test_update_export_deleted_document(self) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
manifest = self._do_export()
|
manifest = self._do_export()
|
||||||
|
|
||||||
@@ -511,8 +519,7 @@ class TestExportImport(
|
|||||||
|
|
||||||
@override_settings(FILENAME_FORMAT="{title}/{correspondent}")
|
@override_settings(FILENAME_FORMAT="{title}/{correspondent}")
|
||||||
def test_update_export_changed_location(self) -> None:
|
def test_update_export_changed_location(self) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
self._do_export(use_filename_format=True)
|
self._do_export(use_filename_format=True)
|
||||||
self.assertIsFile(self.target / "wow1" / "c.pdf")
|
self.assertIsFile(self.target / "wow1" / "c.pdf")
|
||||||
@@ -553,8 +560,7 @@ class TestExportImport(
|
|||||||
- Zipfile is created
|
- Zipfile is created
|
||||||
- Zipfile contains exported files
|
- Zipfile contains exported files
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
args = ["document_exporter", self.target, "--zip"]
|
args = ["document_exporter", self.target, "--zip"]
|
||||||
|
|
||||||
@@ -582,8 +588,7 @@ class TestExportImport(
|
|||||||
- Zipfile is created
|
- Zipfile is created
|
||||||
- Zipfile contains exported files
|
- Zipfile contains exported files
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
args = ["document_exporter", self.target, "--zip", "--use-filename-format"]
|
args = ["document_exporter", self.target, "--zip", "--use-filename-format"]
|
||||||
|
|
||||||
@@ -618,8 +623,7 @@ class TestExportImport(
|
|||||||
- Zipfile contains exported files
|
- Zipfile contains exported files
|
||||||
- The existing file and directory in target are removed
|
- The existing file and directory in target are removed
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
# Create stuff in target directory
|
# Create stuff in target directory
|
||||||
existing_file = self.target / "test.txt"
|
existing_file = self.target / "test.txt"
|
||||||
@@ -714,8 +718,7 @@ class TestExportImport(
|
|||||||
- Manifest.json doesn't contain information about archive files
|
- Manifest.json doesn't contain information about archive files
|
||||||
- Documents can be imported again
|
- Documents can be imported again
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
manifest = self._do_export()
|
manifest = self._do_export()
|
||||||
has_archive = False
|
has_archive = False
|
||||||
@@ -757,8 +760,7 @@ class TestExportImport(
|
|||||||
- Manifest.json doesn't contain information about thumbnails
|
- Manifest.json doesn't contain information about thumbnails
|
||||||
- Documents can be imported again
|
- Documents can be imported again
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
manifest = self._do_export()
|
manifest = self._do_export()
|
||||||
has_thumbnail = False
|
has_thumbnail = False
|
||||||
@@ -802,8 +804,7 @@ class TestExportImport(
|
|||||||
- Main manifest.json file doesn't contain information about documents
|
- Main manifest.json file doesn't contain information about documents
|
||||||
- Documents can be imported again
|
- Documents can be imported again
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
manifest = self._do_export(split_manifest=True)
|
manifest = self._do_export(split_manifest=True)
|
||||||
has_document = False
|
has_document = False
|
||||||
@@ -827,8 +828,7 @@ class TestExportImport(
|
|||||||
self.assertEqual(CustomFieldInstance.objects.count(), 1)
|
self.assertEqual(CustomFieldInstance.objects.count(), 1)
|
||||||
|
|
||||||
def _export_import_barcodes(self, *, split_manifest: bool) -> None:
|
def _export_import_barcodes(self, *, split_manifest: bool) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
DocumentBarcodeFactory(document=self.d1, value="https://example.com")
|
DocumentBarcodeFactory(document=self.d1, value="https://example.com")
|
||||||
DocumentBarcodeFactory(document=self.d2, page=2, value="DE8937")
|
DocumentBarcodeFactory(document=self.d2, page=2, value="DE8937")
|
||||||
|
|
||||||
@@ -863,8 +863,7 @@ class TestExportImport(
|
|||||||
THEN:
|
THEN:
|
||||||
- Documents can be imported again
|
- Documents can be imported again
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
self._do_export(use_folder_prefix=True)
|
self._do_export(use_folder_prefix=True)
|
||||||
|
|
||||||
@@ -890,8 +889,7 @@ class TestExportImport(
|
|||||||
THEN:
|
THEN:
|
||||||
- Documents can be imported again
|
- Documents can be imported again
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
self._do_export(use_folder_prefix=True, split_manifest=True)
|
self._do_export(use_folder_prefix=True, split_manifest=True)
|
||||||
|
|
||||||
@@ -917,8 +915,7 @@ class TestExportImport(
|
|||||||
- ContentType & Permission objects are not deleted, db transaction rolled back
|
- ContentType & Permission objects are not deleted, db transaction rolled back
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
num_content_type_objects = ContentType.objects.count()
|
num_content_type_objects = ContentType.objects.count()
|
||||||
num_permission_objects = Permission.objects.count()
|
num_permission_objects = Permission.objects.count()
|
||||||
@@ -954,8 +951,7 @@ class TestExportImport(
|
|||||||
self.assertEqual(Permission.objects.count(), num_permission_objects + 1)
|
self.assertEqual(Permission.objects.count(), num_permission_objects + 1)
|
||||||
|
|
||||||
def test_exporter_with_auditlog_disabled(self) -> None:
|
def test_exporter_with_auditlog_disabled(self) -> None:
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
with override_settings(
|
with override_settings(
|
||||||
AUDIT_LOG_ENABLED=False,
|
AUDIT_LOG_ENABLED=False,
|
||||||
@@ -974,8 +970,7 @@ class TestExportImport(
|
|||||||
- The soft-deleted document, note, and custom field instance
|
- The soft-deleted document, note, and custom field instance
|
||||||
survive the round-trip with deleted_at preserved
|
survive the round-trip with deleted_at preserved
|
||||||
"""
|
"""
|
||||||
shutil.rmtree(Path(self.dirs.media_dir) / "documents")
|
self._install_sample_files()
|
||||||
install_document_samples(Path(self.dirs.media_dir) / "documents")
|
|
||||||
|
|
||||||
# d1 has self.note and self.cfi1 attached via setUp
|
# d1 has self.note and self.cfi1 attached via setUp
|
||||||
self.d1.delete()
|
self.d1.delete()
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ class TestFuzzyMatchCommand(TestCase):
|
|||||||
call_command(
|
call_command(
|
||||||
"document_fuzzy_match",
|
"document_fuzzy_match",
|
||||||
"--no-progress-bar",
|
"--no-progress-bar",
|
||||||
|
# The default scales with the CPU count and forks, which closes
|
||||||
|
# the test's database connection on PostgreSQL
|
||||||
|
"--processes",
|
||||||
|
"1",
|
||||||
*args,
|
*args,
|
||||||
stdout=stdout,
|
stdout=stdout,
|
||||||
stderr=stderr,
|
stderr=stderr,
|
||||||
|
|||||||
@@ -425,26 +425,29 @@ class TestRetaggerStoragePath(DirectoriesMixin):
|
|||||||
@pytest.mark.management
|
@pytest.mark.management
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
class TestRetaggerIdRange(DirectoriesMixin):
|
class TestRetaggerIdRange(DirectoriesMixin):
|
||||||
@pytest.mark.usefixtures("documents")
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("id_range_args", "expected_count"),
|
("range_end", "expected_count"),
|
||||||
[
|
[
|
||||||
pytest.param(["1", "2"], 1, id="narrow_range_limits_scope"),
|
pytest.param("second", 1, id="narrow_range_limits_scope"),
|
||||||
pytest.param(["1", "9999"], 2, id="wide_range_tags_all_matches"),
|
pytest.param("extra", 2, id="wide_range_tags_all_matches"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_id_range_limits_scope(
|
def test_id_range_limits_scope(
|
||||||
self,
|
self,
|
||||||
tags: TagTuple,
|
tags: TagTuple,
|
||||||
id_range_args: list[str],
|
documents: DocumentTuple,
|
||||||
|
range_end: str,
|
||||||
expected_count: int,
|
expected_count: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
DocumentFactory(content="NOT the first document")
|
first, second, *_ = documents
|
||||||
|
extra = DocumentFactory(content="NOT the first document")
|
||||||
|
end = {"second": second, "extra": extra}[range_end]
|
||||||
call_command(
|
call_command(
|
||||||
"document_retagger",
|
"document_retagger",
|
||||||
"--tags",
|
"--tags",
|
||||||
"--id-range",
|
"--id-range",
|
||||||
*id_range_args,
|
str(first.pk),
|
||||||
|
str(end.pk),
|
||||||
skip_checks=True,
|
skip_checks=True,
|
||||||
)
|
)
|
||||||
tag_first, *_ = tags
|
tag_first, *_ = tags
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import re
|
||||||
|
from fnmatch import fnmatch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from documents.matching import glob_to_database_regex
|
||||||
|
from documents.models import Document
|
||||||
|
from paperless_testing.factories import DocumentFactory
|
||||||
|
|
||||||
|
NAMES = [
|
||||||
|
"invoice.pdf",
|
||||||
|
"Invoice.PDF",
|
||||||
|
"invoice_2024.pdf",
|
||||||
|
"a.b.c",
|
||||||
|
"a-b",
|
||||||
|
"sample [1].pdf",
|
||||||
|
"sample 1.pdf",
|
||||||
|
"x^y",
|
||||||
|
"back\\slash",
|
||||||
|
"dir/file.pdf",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
|
||||||
|
PATTERNS = [
|
||||||
|
"*",
|
||||||
|
"invoice.pdf",
|
||||||
|
"*.pdf",
|
||||||
|
"*invoice*pdf",
|
||||||
|
"*a*b*c*",
|
||||||
|
"invoice_????.pdf",
|
||||||
|
"sample [[]1].pdf",
|
||||||
|
"sample [1-2].pdf",
|
||||||
|
"sample [!2].pdf",
|
||||||
|
"sample [^2].pdf",
|
||||||
|
"sample [",
|
||||||
|
"a.b.c",
|
||||||
|
"x^y",
|
||||||
|
"back\\slash",
|
||||||
|
"[]]",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("pattern", PATTERNS)
|
||||||
|
def test_regex_agrees_with_fnmatch(pattern: str) -> None:
|
||||||
|
regex = glob_to_database_regex(pattern)
|
||||||
|
for name in NAMES:
|
||||||
|
expected = fnmatch(name.lower(), pattern.lower())
|
||||||
|
actual = re.search(regex, name, re.IGNORECASE) is not None
|
||||||
|
assert actual is expected, f"{pattern!r} vs {name!r}"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("pattern", ["*", "*a*b*c*", "a*b*c*d*e"])
|
||||||
|
def test_regex_avoids_syntax_postgresql_rejects(pattern: str) -> None:
|
||||||
|
regex = glob_to_database_regex(pattern)
|
||||||
|
assert not any(marker in regex for marker in ("(?", "\\Z"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_database_filter_matches_glob() -> None:
|
||||||
|
matching = DocumentFactory(original_filename="Invoice_2024.PDF")
|
||||||
|
DocumentFactory(original_filename="invoice_2024.txt")
|
||||||
|
DocumentFactory(original_filename="receipt.pdf")
|
||||||
|
|
||||||
|
found = Document.objects.filter(
|
||||||
|
original_filename__iregex=glob_to_database_regex("*invoice*.pdf"),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert list(found) == [matching]
|
||||||
@@ -572,7 +572,7 @@ class TestAiChatAllDocumentsPermissionBoundary:
|
|||||||
ENDPOINT = "/api/documents/chat/"
|
ENDPOINT = "/api/documents/chat/"
|
||||||
|
|
||||||
@override_settings(AI_ENABLED=True)
|
@override_settings(AI_ENABLED=True)
|
||||||
@patch("paperless_ai.chat.stream_chat_with_documents")
|
@patch("documents.views.stream_chat_with_documents")
|
||||||
def test_chat_all_documents_excludes_unshared_document(self, mock_stream_chat):
|
def test_chat_all_documents_excludes_unshared_document(self, mock_stream_chat):
|
||||||
mock_stream_chat.return_value = iter([b"data"])
|
mock_stream_chat.return_value = iter([b"data"])
|
||||||
|
|
||||||
|
|||||||
Loaded 100 of 170 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user