diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf index 439b83908..ea44b87bf 100644 --- a/src-ui/messages.xlf +++ b/src-ui/messages.xlf @@ -3444,7 +3444,7 @@ src/app/components/common/dates-dropdown/dates-dropdown.component.ts - 111 + 113 src/app/components/common/input/date/date.component.html @@ -3704,14 +3704,14 @@ This month src/app/components/common/dates-dropdown/dates-dropdown.component.ts - 106 + 107 Yesterday src/app/components/common/dates-dropdown/dates-dropdown.component.ts - 116 + 118 src/app/pipes/custom-date.pipe.ts @@ -3722,28 +3722,28 @@ Previous week src/app/components/common/dates-dropdown/dates-dropdown.component.ts - 121 + 123 Previous month src/app/components/common/dates-dropdown/dates-dropdown.component.ts - 135 + 137 Previous quarter src/app/components/common/dates-dropdown/dates-dropdown.component.ts - 141 + 143 Previous year src/app/components/common/dates-dropdown/dates-dropdown.component.ts - 155 + 157 diff --git a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.html b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.html index 74b49bbdb..2057a79ff 100644 --- a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.html +++ b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.html @@ -164,9 +164,11 @@ {{ item.name }} @if (item.dateEnd) { - {{ item.date | customDate:'MMM d' }} – {{ item.dateEnd | customDate:'mediumDate' }} + {{ item.date | customDate:'mediumDate' }} – {{ item.dateEnd | customDate:'mediumDate' }} + } @else if (item.dateTilNow) { + {{ item.dateTilNow | customDate:'mediumDate' }} – now } @else { - {{ item.date | customDate:'mediumDate' }} – now + {{ item.date | customDate:'mediumDate' }} } diff --git a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts index e07b08959..42bd3b0e4 100644 --- a/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts +++ b/src-ui/src/app/components/common/dates-dropdown/dates-dropdown.component.ts @@ -79,32 +79,34 @@ export class DatesDropdownComponent implements OnInit, OnDestroy { { id: RelativeDate.WITHIN_1_WEEK, name: $localize`Within 1 week`, - date: new Date().setDate(new Date().getDate() - 7), + dateTilNow: new Date().setDate(new Date().getDate() - 7), }, { id: RelativeDate.WITHIN_1_MONTH, name: $localize`Within 1 month`, - date: new Date().setMonth(new Date().getMonth() - 1), + dateTilNow: new Date().setMonth(new Date().getMonth() - 1), }, { id: RelativeDate.WITHIN_3_MONTHS, name: $localize`Within 3 months`, - date: new Date().setMonth(new Date().getMonth() - 3), + dateTilNow: new Date().setMonth(new Date().getMonth() - 3), }, { id: RelativeDate.WITHIN_1_YEAR, name: $localize`Within 1 year`, - date: new Date().setFullYear(new Date().getFullYear() - 1), + dateTilNow: new Date().setFullYear(new Date().getFullYear() - 1), }, { id: RelativeDate.THIS_YEAR, name: $localize`This year`, date: new Date('1/1/' + new Date().getFullYear()), + dateEnd: new Date('12/31/' + new Date().getFullYear()), }, { id: RelativeDate.THIS_MONTH, name: $localize`This month`, date: new Date().setDate(1), + dateEnd: new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0), }, { id: RelativeDate.TODAY, diff --git a/src/documents/migrations/0007_document_content_length.py b/src/documents/migrations/0007_document_content_length.py new file mode 100644 index 000000000..c294afca5 --- /dev/null +++ b/src/documents/migrations/0007_document_content_length.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.6 on 2026-01-24 07:33 + +import django.db.models.functions.text +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + dependencies = [ + ("documents", "0006_alter_document_checksum_unique"), + ] + + operations = [ + migrations.AddField( + model_name="document", + name="content_length", + field=models.GeneratedField( + db_persist=True, + expression=django.db.models.functions.text.Length("content"), + null=False, + help_text="Length of the content field in characters. Automatically maintained by the database for faster statistics computation.", + output_field=models.PositiveIntegerField(default=0), + ), + ), + ] diff --git a/src/documents/models.py b/src/documents/models.py index d91a8f861..29be2ed46 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -20,7 +20,9 @@ if settings.AUDIT_LOG_ENABLED: from auditlog.registry import auditlog from django.db.models import Case +from django.db.models import PositiveIntegerField from django.db.models.functions import Cast +from django.db.models.functions import Length from django.db.models.functions import Substr from django_softdelete.models import SoftDeleteModel @@ -192,6 +194,15 @@ class Document(SoftDeleteModel, ModelWithOwner): ), ) + content_length = models.GeneratedField( + expression=Length("content"), + output_field=PositiveIntegerField(default=0), + db_persist=True, + null=False, + serialize=False, + help_text="Length of the content field in characters. Automatically maintained by the database for faster statistics computation.", + ) + mime_type = models.CharField(_("mime type"), max_length=256, editable=False) tags = models.ManyToManyField( @@ -1057,7 +1068,7 @@ if settings.AUDIT_LOG_ENABLED: auditlog.register( Document, m2m_fields={"tags"}, - exclude_fields=["modified"], + exclude_fields=["content_length", "modified"], ) auditlog.register(Correspondent) auditlog.register(Tag) diff --git a/src/documents/tests/test_api_documents.py b/src/documents/tests/test_api_documents.py index f40ef157f..96d22dc2c 100644 --- a/src/documents/tests/test_api_documents.py +++ b/src/documents/tests/test_api_documents.py @@ -131,6 +131,10 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase): self.assertIn("content", results_full[0]) self.assertIn("id", results_full[0]) + # Content length is used internally for performance reasons. + # No need to expose this field. + self.assertNotIn("content_length", results_full[0]) + response = self.client.get("/api/documents/?fields=id", format="json") self.assertEqual(response.status_code, status.HTTP_200_OK) results = response.data["results"] diff --git a/src/documents/tests/test_management_exporter.py b/src/documents/tests/test_management_exporter.py index 81262779a..c2a1360ca 100644 --- a/src/documents/tests/test_management_exporter.py +++ b/src/documents/tests/test_management_exporter.py @@ -241,6 +241,10 @@ class TestExportImport( checksum = hashlib.md5(f.read()).hexdigest() self.assertEqual(checksum, element["fields"]["checksum"]) + # Generated field "content_length" should not be exported, + # it is automatically computed during import. + self.assertNotIn("content_length", element["fields"]) + if document_exporter.EXPORTER_ARCHIVE_NAME in element: fname = ( self.target / element[document_exporter.EXPORTER_ARCHIVE_NAME] diff --git a/src/documents/views.py b/src/documents/views.py index f6e19d1e2..61568011c 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -35,7 +35,6 @@ from django.db.models import Model from django.db.models import Q from django.db.models import Sum from django.db.models import When -from django.db.models.functions import Length from django.db.models.functions import Lower from django.db.models.manager import Manager from django.http import FileResponse @@ -2332,23 +2331,19 @@ class StatisticsView(GenericAPIView): user = request.user if request.user is not None else None documents = ( - ( - Document.objects.all() - if user is None - else get_objects_for_user_owner_aware( - user, - "documents.view_document", - Document, - ) + Document.objects.all() + if user is None + else get_objects_for_user_owner_aware( + user, + "documents.view_document", + Document, ) - .only("mime_type", "content") - .prefetch_related("tags") ) tags = ( Tag.objects.all() if user is None else get_objects_for_user_owner_aware(user, "documents.view_tag", Tag) - ) + ).only("id", "is_inbox_tag") correspondent_count = ( Correspondent.objects.count() if user is None @@ -2377,31 +2372,33 @@ class StatisticsView(GenericAPIView): ).count() ) - documents_total = documents.count() - - inbox_tags = tags.filter(is_inbox_tag=True) + inbox_tag_pks = list( + tags.filter(is_inbox_tag=True).values_list("pk", flat=True), + ) documents_inbox = ( - documents.filter(tags__id__in=inbox_tags).distinct().count() - if inbox_tags.exists() + documents.filter(tags__id__in=inbox_tag_pks).values("id").distinct().count() + if inbox_tag_pks else None ) - document_file_type_counts = ( + # Single SQL request for document stats and mime type counts + mime_type_stats = list( documents.values("mime_type") - .annotate(mime_type_count=Count("mime_type")) - .order_by("-mime_type_count") - if documents_total > 0 - else [] + .annotate( + mime_type_count=Count("id"), + mime_type_chars=Sum("content_length"), + ) + .order_by("-mime_type_count"), ) - character_count = ( - documents.annotate( - characters=Length("content"), - ) - .aggregate(Sum("characters")) - .get("characters__sum") - ) + # Calculate totals from grouped results + documents_total = sum(row["mime_type_count"] for row in mime_type_stats) + character_count = sum(row["mime_type_chars"] or 0 for row in mime_type_stats) + document_file_type_counts = [ + {"mime_type": row["mime_type"], "mime_type_count": row["mime_type_count"]} + for row in mime_type_stats + ] current_asn = Document.objects.aggregate( Max("archive_serial_number", default=0), @@ -2414,11 +2411,9 @@ class StatisticsView(GenericAPIView): "documents_total": documents_total, "documents_inbox": documents_inbox, "inbox_tag": ( - inbox_tags.first().pk if inbox_tags.exists() else None + inbox_tag_pks[0] if inbox_tag_pks else None ), # backwards compatibility - "inbox_tags": ( - [tag.pk for tag in inbox_tags] if inbox_tags.exists() else None - ), + "inbox_tags": (inbox_tag_pks if inbox_tag_pks else None), "document_file_type_counts": document_file_type_counts, "character_count": character_count, "tag_count": len(tags), diff --git a/src/locale/en_US/LC_MESSAGES/django.po b/src/locale/en_US/LC_MESSAGES/django.po index 41a007ebd..5bdd1ccf9 100644 --- a/src/locale/en_US/LC_MESSAGES/django.po +++ b/src/locale/en_US/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: paperless-ngx\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-01-26 18:56+0000\n" +"POT-Creation-Date: 2026-01-26 20:11+0000\n" "PO-Revision-Date: 2022-02-17 04:17\n" "Last-Translator: \n" "Language-Team: English\n" @@ -49,7 +49,7 @@ msgstr "" msgid "{data_type} does not support query expr {expr!r}." msgstr "" -#: documents/filters.py:669 documents/models.py:135 +#: documents/filters.py:669 documents/models.py:137 msgid "Maximum nesting depth exceeded." msgstr "" @@ -57,1170 +57,1170 @@ msgstr "" msgid "Custom field not found" msgstr "" -#: documents/models.py:38 documents/models.py:746 +#: documents/models.py:40 documents/models.py:757 msgid "owner" msgstr "" -#: documents/models.py:55 documents/models.py:961 +#: documents/models.py:57 documents/models.py:972 msgid "None" msgstr "" -#: documents/models.py:56 documents/models.py:962 +#: documents/models.py:58 documents/models.py:973 msgid "Any word" msgstr "" -#: documents/models.py:57 documents/models.py:963 +#: documents/models.py:59 documents/models.py:974 msgid "All words" msgstr "" -#: documents/models.py:58 documents/models.py:964 +#: documents/models.py:60 documents/models.py:975 msgid "Exact match" msgstr "" -#: documents/models.py:59 documents/models.py:965 +#: documents/models.py:61 documents/models.py:976 msgid "Regular expression" msgstr "" -#: documents/models.py:60 documents/models.py:966 +#: documents/models.py:62 documents/models.py:977 msgid "Fuzzy word" msgstr "" -#: documents/models.py:61 +#: documents/models.py:63 msgid "Automatic" msgstr "" -#: documents/models.py:64 documents/models.py:433 documents/models.py:1527 +#: documents/models.py:66 documents/models.py:444 documents/models.py:1538 #: paperless_mail/models.py:23 paperless_mail/models.py:143 msgid "name" msgstr "" -#: documents/models.py:66 documents/models.py:1030 +#: documents/models.py:68 documents/models.py:1041 msgid "match" msgstr "" -#: documents/models.py:69 documents/models.py:1033 +#: documents/models.py:71 documents/models.py:1044 msgid "matching algorithm" msgstr "" -#: documents/models.py:74 documents/models.py:1038 +#: documents/models.py:76 documents/models.py:1049 msgid "is insensitive" msgstr "" -#: documents/models.py:97 documents/models.py:163 +#: documents/models.py:99 documents/models.py:165 msgid "correspondent" msgstr "" -#: documents/models.py:98 +#: documents/models.py:100 msgid "correspondents" msgstr "" -#: documents/models.py:102 +#: documents/models.py:104 msgid "color" msgstr "" -#: documents/models.py:107 +#: documents/models.py:109 msgid "is inbox tag" msgstr "" -#: documents/models.py:110 +#: documents/models.py:112 msgid "" "Marks this tag as an inbox tag: All newly consumed documents will be tagged " "with inbox tags." msgstr "" -#: documents/models.py:116 +#: documents/models.py:118 msgid "tag" msgstr "" -#: documents/models.py:117 documents/models.py:201 +#: documents/models.py:119 documents/models.py:212 msgid "tags" msgstr "" -#: documents/models.py:123 +#: documents/models.py:125 msgid "Cannot set itself as parent." msgstr "" -#: documents/models.py:125 +#: documents/models.py:127 msgid "Cannot set parent to a descendant." msgstr "" -#: documents/models.py:142 documents/models.py:183 +#: documents/models.py:144 documents/models.py:185 msgid "document type" msgstr "" -#: documents/models.py:143 +#: documents/models.py:145 msgid "document types" msgstr "" -#: documents/models.py:148 +#: documents/models.py:150 msgid "path" msgstr "" -#: documents/models.py:152 documents/models.py:172 +#: documents/models.py:154 documents/models.py:174 msgid "storage path" msgstr "" -#: documents/models.py:153 +#: documents/models.py:155 msgid "storage paths" msgstr "" -#: documents/models.py:175 +#: documents/models.py:177 msgid "title" msgstr "" -#: documents/models.py:187 documents/models.py:660 +#: documents/models.py:189 documents/models.py:671 msgid "content" msgstr "" -#: documents/models.py:190 +#: documents/models.py:192 msgid "" "The raw, text-only data of the document. This field is primarily used for " "searching." msgstr "" -#: documents/models.py:195 +#: documents/models.py:206 msgid "mime type" msgstr "" -#: documents/models.py:205 +#: documents/models.py:216 msgid "checksum" msgstr "" -#: documents/models.py:208 +#: documents/models.py:219 msgid "The checksum of the original document." msgstr "" -#: documents/models.py:212 +#: documents/models.py:223 msgid "archive checksum" msgstr "" -#: documents/models.py:217 +#: documents/models.py:228 msgid "The checksum of the archived document." msgstr "" -#: documents/models.py:221 +#: documents/models.py:232 msgid "page count" msgstr "" -#: documents/models.py:228 +#: documents/models.py:239 msgid "The number of pages of the document." msgstr "" -#: documents/models.py:233 documents/models.py:666 documents/models.py:704 -#: documents/models.py:776 documents/models.py:835 +#: documents/models.py:244 documents/models.py:677 documents/models.py:715 +#: documents/models.py:787 documents/models.py:846 msgid "created" msgstr "" -#: documents/models.py:239 +#: documents/models.py:250 msgid "modified" msgstr "" -#: documents/models.py:246 +#: documents/models.py:257 msgid "added" msgstr "" -#: documents/models.py:253 +#: documents/models.py:264 msgid "filename" msgstr "" -#: documents/models.py:259 +#: documents/models.py:270 msgid "Current filename in storage" msgstr "" -#: documents/models.py:263 +#: documents/models.py:274 msgid "archive filename" msgstr "" -#: documents/models.py:269 +#: documents/models.py:280 msgid "Current archive filename in storage" msgstr "" -#: documents/models.py:273 +#: documents/models.py:284 msgid "original filename" msgstr "" -#: documents/models.py:279 +#: documents/models.py:290 msgid "The original name of the file when it was uploaded" msgstr "" -#: documents/models.py:286 +#: documents/models.py:297 msgid "archive serial number" msgstr "" -#: documents/models.py:296 +#: documents/models.py:307 msgid "The position of this document in your physical document archive." msgstr "" -#: documents/models.py:302 documents/models.py:677 documents/models.py:731 -#: documents/models.py:1570 +#: documents/models.py:313 documents/models.py:688 documents/models.py:742 +#: documents/models.py:1581 msgid "document" msgstr "" -#: documents/models.py:303 +#: documents/models.py:314 msgid "documents" msgstr "" -#: documents/models.py:414 +#: documents/models.py:425 msgid "Table" msgstr "" -#: documents/models.py:415 +#: documents/models.py:426 msgid "Small Cards" msgstr "" -#: documents/models.py:416 +#: documents/models.py:427 msgid "Large Cards" msgstr "" -#: documents/models.py:419 +#: documents/models.py:430 msgid "Title" msgstr "" -#: documents/models.py:420 documents/models.py:982 +#: documents/models.py:431 documents/models.py:993 msgid "Created" msgstr "" -#: documents/models.py:421 documents/models.py:981 +#: documents/models.py:432 documents/models.py:992 msgid "Added" msgstr "" -#: documents/models.py:422 +#: documents/models.py:433 msgid "Tags" msgstr "" -#: documents/models.py:423 +#: documents/models.py:434 msgid "Correspondent" msgstr "" -#: documents/models.py:424 +#: documents/models.py:435 msgid "Document Type" msgstr "" -#: documents/models.py:425 +#: documents/models.py:436 msgid "Storage Path" msgstr "" -#: documents/models.py:426 +#: documents/models.py:437 msgid "Note" msgstr "" -#: documents/models.py:427 +#: documents/models.py:438 msgid "Owner" msgstr "" -#: documents/models.py:428 +#: documents/models.py:439 msgid "Shared" msgstr "" -#: documents/models.py:429 +#: documents/models.py:440 msgid "ASN" msgstr "" -#: documents/models.py:430 +#: documents/models.py:441 msgid "Pages" msgstr "" -#: documents/models.py:436 +#: documents/models.py:447 msgid "show on dashboard" msgstr "" -#: documents/models.py:439 +#: documents/models.py:450 msgid "show in sidebar" msgstr "" -#: documents/models.py:443 +#: documents/models.py:454 msgid "sort field" msgstr "" -#: documents/models.py:448 +#: documents/models.py:459 msgid "sort reverse" msgstr "" -#: documents/models.py:451 +#: documents/models.py:462 msgid "View page size" msgstr "" -#: documents/models.py:459 +#: documents/models.py:470 msgid "View display mode" msgstr "" -#: documents/models.py:466 +#: documents/models.py:477 msgid "Document display fields" msgstr "" -#: documents/models.py:473 documents/models.py:536 +#: documents/models.py:484 documents/models.py:547 msgid "saved view" msgstr "" -#: documents/models.py:474 +#: documents/models.py:485 msgid "saved views" msgstr "" -#: documents/models.py:482 +#: documents/models.py:493 msgid "title contains" msgstr "" -#: documents/models.py:483 +#: documents/models.py:494 msgid "content contains" msgstr "" -#: documents/models.py:484 +#: documents/models.py:495 msgid "ASN is" msgstr "" -#: documents/models.py:485 +#: documents/models.py:496 msgid "correspondent is" msgstr "" -#: documents/models.py:486 +#: documents/models.py:497 msgid "document type is" msgstr "" -#: documents/models.py:487 +#: documents/models.py:498 msgid "is in inbox" msgstr "" -#: documents/models.py:488 +#: documents/models.py:499 msgid "has tag" msgstr "" -#: documents/models.py:489 +#: documents/models.py:500 msgid "has any tag" msgstr "" -#: documents/models.py:490 +#: documents/models.py:501 msgid "created before" msgstr "" -#: documents/models.py:491 +#: documents/models.py:502 msgid "created after" msgstr "" -#: documents/models.py:492 +#: documents/models.py:503 msgid "created year is" msgstr "" -#: documents/models.py:493 +#: documents/models.py:504 msgid "created month is" msgstr "" -#: documents/models.py:494 +#: documents/models.py:505 msgid "created day is" msgstr "" -#: documents/models.py:495 +#: documents/models.py:506 msgid "added before" msgstr "" -#: documents/models.py:496 +#: documents/models.py:507 msgid "added after" msgstr "" -#: documents/models.py:497 +#: documents/models.py:508 msgid "modified before" msgstr "" -#: documents/models.py:498 +#: documents/models.py:509 msgid "modified after" msgstr "" -#: documents/models.py:499 +#: documents/models.py:510 msgid "does not have tag" msgstr "" -#: documents/models.py:500 +#: documents/models.py:511 msgid "does not have ASN" msgstr "" -#: documents/models.py:501 +#: documents/models.py:512 msgid "title or content contains" msgstr "" -#: documents/models.py:502 +#: documents/models.py:513 msgid "fulltext query" msgstr "" -#: documents/models.py:503 +#: documents/models.py:514 msgid "more like this" msgstr "" -#: documents/models.py:504 +#: documents/models.py:515 msgid "has tags in" msgstr "" -#: documents/models.py:505 +#: documents/models.py:516 msgid "ASN greater than" msgstr "" -#: documents/models.py:506 +#: documents/models.py:517 msgid "ASN less than" msgstr "" -#: documents/models.py:507 +#: documents/models.py:518 msgid "storage path is" msgstr "" -#: documents/models.py:508 +#: documents/models.py:519 msgid "has correspondent in" msgstr "" -#: documents/models.py:509 +#: documents/models.py:520 msgid "does not have correspondent in" msgstr "" -#: documents/models.py:510 +#: documents/models.py:521 msgid "has document type in" msgstr "" -#: documents/models.py:511 +#: documents/models.py:522 msgid "does not have document type in" msgstr "" -#: documents/models.py:512 +#: documents/models.py:523 msgid "has storage path in" msgstr "" -#: documents/models.py:513 +#: documents/models.py:524 msgid "does not have storage path in" msgstr "" -#: documents/models.py:514 +#: documents/models.py:525 msgid "owner is" msgstr "" -#: documents/models.py:515 +#: documents/models.py:526 msgid "has owner in" msgstr "" -#: documents/models.py:516 +#: documents/models.py:527 msgid "does not have owner" msgstr "" -#: documents/models.py:517 +#: documents/models.py:528 msgid "does not have owner in" msgstr "" -#: documents/models.py:518 +#: documents/models.py:529 msgid "has custom field value" msgstr "" -#: documents/models.py:519 +#: documents/models.py:530 msgid "is shared by me" msgstr "" -#: documents/models.py:520 +#: documents/models.py:531 msgid "has custom fields" msgstr "" -#: documents/models.py:521 +#: documents/models.py:532 msgid "has custom field in" msgstr "" -#: documents/models.py:522 +#: documents/models.py:533 msgid "does not have custom field in" msgstr "" -#: documents/models.py:523 +#: documents/models.py:534 msgid "does not have custom field" msgstr "" -#: documents/models.py:524 +#: documents/models.py:535 msgid "custom fields query" msgstr "" -#: documents/models.py:525 +#: documents/models.py:536 msgid "created to" msgstr "" -#: documents/models.py:526 +#: documents/models.py:537 msgid "created from" msgstr "" -#: documents/models.py:527 +#: documents/models.py:538 msgid "added to" msgstr "" -#: documents/models.py:528 +#: documents/models.py:539 msgid "added from" msgstr "" -#: documents/models.py:529 +#: documents/models.py:540 msgid "mime type is" msgstr "" -#: documents/models.py:539 +#: documents/models.py:550 msgid "rule type" msgstr "" -#: documents/models.py:541 +#: documents/models.py:552 msgid "value" msgstr "" -#: documents/models.py:544 +#: documents/models.py:555 msgid "filter rule" msgstr "" -#: documents/models.py:545 +#: documents/models.py:556 msgid "filter rules" msgstr "" -#: documents/models.py:569 +#: documents/models.py:580 msgid "Auto Task" msgstr "" -#: documents/models.py:570 +#: documents/models.py:581 msgid "Scheduled Task" msgstr "" -#: documents/models.py:571 +#: documents/models.py:582 msgid "Manual Task" msgstr "" -#: documents/models.py:574 +#: documents/models.py:585 msgid "Consume File" msgstr "" -#: documents/models.py:575 +#: documents/models.py:586 msgid "Train Classifier" msgstr "" -#: documents/models.py:576 +#: documents/models.py:587 msgid "Check Sanity" msgstr "" -#: documents/models.py:577 +#: documents/models.py:588 msgid "Index Optimize" msgstr "" -#: documents/models.py:578 +#: documents/models.py:589 msgid "LLM Index Update" msgstr "" -#: documents/models.py:583 +#: documents/models.py:594 msgid "Task ID" msgstr "" -#: documents/models.py:584 +#: documents/models.py:595 msgid "Celery ID for the Task that was run" msgstr "" -#: documents/models.py:589 +#: documents/models.py:600 msgid "Acknowledged" msgstr "" -#: documents/models.py:590 +#: documents/models.py:601 msgid "If the task is acknowledged via the frontend or API" msgstr "" -#: documents/models.py:596 +#: documents/models.py:607 msgid "Task Filename" msgstr "" -#: documents/models.py:597 +#: documents/models.py:608 msgid "Name of the file which the Task was run for" msgstr "" -#: documents/models.py:604 +#: documents/models.py:615 msgid "Task Name" msgstr "" -#: documents/models.py:605 +#: documents/models.py:616 msgid "Name of the task that was run" msgstr "" -#: documents/models.py:612 +#: documents/models.py:623 msgid "Task State" msgstr "" -#: documents/models.py:613 +#: documents/models.py:624 msgid "Current state of the task being run" msgstr "" -#: documents/models.py:619 +#: documents/models.py:630 msgid "Created DateTime" msgstr "" -#: documents/models.py:620 +#: documents/models.py:631 msgid "Datetime field when the task result was created in UTC" msgstr "" -#: documents/models.py:626 +#: documents/models.py:637 msgid "Started DateTime" msgstr "" -#: documents/models.py:627 +#: documents/models.py:638 msgid "Datetime field when the task was started in UTC" msgstr "" -#: documents/models.py:633 +#: documents/models.py:644 msgid "Completed DateTime" msgstr "" -#: documents/models.py:634 +#: documents/models.py:645 msgid "Datetime field when the task was completed in UTC" msgstr "" -#: documents/models.py:640 +#: documents/models.py:651 msgid "Result Data" msgstr "" -#: documents/models.py:642 +#: documents/models.py:653 msgid "The data returned by the task" msgstr "" -#: documents/models.py:650 +#: documents/models.py:661 msgid "Task Type" msgstr "" -#: documents/models.py:651 +#: documents/models.py:662 msgid "The type of task that was run" msgstr "" -#: documents/models.py:662 +#: documents/models.py:673 msgid "Note for the document" msgstr "" -#: documents/models.py:686 +#: documents/models.py:697 msgid "user" msgstr "" -#: documents/models.py:691 +#: documents/models.py:702 msgid "note" msgstr "" -#: documents/models.py:692 +#: documents/models.py:703 msgid "notes" msgstr "" -#: documents/models.py:700 +#: documents/models.py:711 msgid "Archive" msgstr "" -#: documents/models.py:701 +#: documents/models.py:712 msgid "Original" msgstr "" -#: documents/models.py:712 paperless_mail/models.py:75 +#: documents/models.py:723 paperless_mail/models.py:75 msgid "expiration" msgstr "" -#: documents/models.py:719 +#: documents/models.py:730 msgid "slug" msgstr "" -#: documents/models.py:751 +#: documents/models.py:762 msgid "share link" msgstr "" -#: documents/models.py:752 +#: documents/models.py:763 msgid "share links" msgstr "" -#: documents/models.py:764 +#: documents/models.py:775 msgid "String" msgstr "" -#: documents/models.py:765 +#: documents/models.py:776 msgid "URL" msgstr "" -#: documents/models.py:766 +#: documents/models.py:777 msgid "Date" msgstr "" -#: documents/models.py:767 +#: documents/models.py:778 msgid "Boolean" msgstr "" -#: documents/models.py:768 +#: documents/models.py:779 msgid "Integer" msgstr "" -#: documents/models.py:769 +#: documents/models.py:780 msgid "Float" msgstr "" -#: documents/models.py:770 +#: documents/models.py:781 msgid "Monetary" msgstr "" -#: documents/models.py:771 +#: documents/models.py:782 msgid "Document Link" msgstr "" -#: documents/models.py:772 +#: documents/models.py:783 msgid "Select" msgstr "" -#: documents/models.py:773 +#: documents/models.py:784 msgid "Long Text" msgstr "" -#: documents/models.py:785 +#: documents/models.py:796 msgid "data type" msgstr "" -#: documents/models.py:792 +#: documents/models.py:803 msgid "extra data" msgstr "" -#: documents/models.py:796 +#: documents/models.py:807 msgid "Extra data for the custom field, such as select options" msgstr "" -#: documents/models.py:802 +#: documents/models.py:813 msgid "custom field" msgstr "" -#: documents/models.py:803 +#: documents/models.py:814 msgid "custom fields" msgstr "" -#: documents/models.py:903 +#: documents/models.py:914 msgid "custom field instance" msgstr "" -#: documents/models.py:904 +#: documents/models.py:915 msgid "custom field instances" msgstr "" -#: documents/models.py:969 +#: documents/models.py:980 msgid "Consumption Started" msgstr "" -#: documents/models.py:970 +#: documents/models.py:981 msgid "Document Added" msgstr "" -#: documents/models.py:971 +#: documents/models.py:982 msgid "Document Updated" msgstr "" -#: documents/models.py:972 +#: documents/models.py:983 msgid "Scheduled" msgstr "" -#: documents/models.py:975 +#: documents/models.py:986 msgid "Consume Folder" msgstr "" -#: documents/models.py:976 +#: documents/models.py:987 msgid "Api Upload" msgstr "" -#: documents/models.py:977 +#: documents/models.py:988 msgid "Mail Fetch" msgstr "" -#: documents/models.py:978 +#: documents/models.py:989 msgid "Web UI" msgstr "" -#: documents/models.py:983 +#: documents/models.py:994 msgid "Modified" msgstr "" -#: documents/models.py:984 +#: documents/models.py:995 msgid "Custom Field" msgstr "" -#: documents/models.py:987 +#: documents/models.py:998 msgid "Workflow Trigger Type" msgstr "" -#: documents/models.py:999 +#: documents/models.py:1010 msgid "filter path" msgstr "" -#: documents/models.py:1004 +#: documents/models.py:1015 msgid "" "Only consume documents with a path that matches this if specified. Wildcards " "specified as * are allowed. Case insensitive." msgstr "" -#: documents/models.py:1011 +#: documents/models.py:1022 msgid "filter filename" msgstr "" -#: documents/models.py:1016 paperless_mail/models.py:200 +#: documents/models.py:1027 paperless_mail/models.py:200 msgid "" "Only consume documents which entirely match this filename if specified. " "Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." msgstr "" -#: documents/models.py:1027 +#: documents/models.py:1038 msgid "filter documents from this mail rule" msgstr "" -#: documents/models.py:1043 +#: documents/models.py:1054 msgid "has these tag(s)" msgstr "" -#: documents/models.py:1050 +#: documents/models.py:1061 msgid "has all of these tag(s)" msgstr "" -#: documents/models.py:1057 +#: documents/models.py:1068 msgid "does not have these tag(s)" msgstr "" -#: documents/models.py:1065 +#: documents/models.py:1076 msgid "has this document type" msgstr "" -#: documents/models.py:1072 +#: documents/models.py:1083 msgid "has one of these document types" msgstr "" -#: documents/models.py:1079 +#: documents/models.py:1090 msgid "does not have these document type(s)" msgstr "" -#: documents/models.py:1087 +#: documents/models.py:1098 msgid "has this correspondent" msgstr "" -#: documents/models.py:1094 +#: documents/models.py:1105 msgid "does not have these correspondent(s)" msgstr "" -#: documents/models.py:1101 +#: documents/models.py:1112 msgid "has one of these correspondents" msgstr "" -#: documents/models.py:1109 +#: documents/models.py:1120 msgid "has this storage path" msgstr "" -#: documents/models.py:1116 +#: documents/models.py:1127 msgid "has one of these storage paths" msgstr "" -#: documents/models.py:1123 +#: documents/models.py:1134 msgid "does not have these storage path(s)" msgstr "" -#: documents/models.py:1127 +#: documents/models.py:1138 msgid "filter custom field query" msgstr "" -#: documents/models.py:1130 +#: documents/models.py:1141 msgid "JSON-encoded custom field query expression." msgstr "" -#: documents/models.py:1134 +#: documents/models.py:1145 msgid "schedule offset days" msgstr "" -#: documents/models.py:1137 +#: documents/models.py:1148 msgid "The number of days to offset the schedule trigger by." msgstr "" -#: documents/models.py:1142 +#: documents/models.py:1153 msgid "schedule is recurring" msgstr "" -#: documents/models.py:1145 +#: documents/models.py:1156 msgid "If the schedule should be recurring." msgstr "" -#: documents/models.py:1150 +#: documents/models.py:1161 msgid "schedule recurring delay in days" msgstr "" -#: documents/models.py:1154 +#: documents/models.py:1165 msgid "The number of days between recurring schedule triggers." msgstr "" -#: documents/models.py:1159 +#: documents/models.py:1170 msgid "schedule date field" msgstr "" -#: documents/models.py:1164 +#: documents/models.py:1175 msgid "The field to check for a schedule trigger." msgstr "" -#: documents/models.py:1173 +#: documents/models.py:1184 msgid "schedule date custom field" msgstr "" -#: documents/models.py:1177 +#: documents/models.py:1188 msgid "workflow trigger" msgstr "" -#: documents/models.py:1178 +#: documents/models.py:1189 msgid "workflow triggers" msgstr "" -#: documents/models.py:1186 +#: documents/models.py:1197 msgid "email subject" msgstr "" -#: documents/models.py:1190 +#: documents/models.py:1201 msgid "" "The subject of the email, can include some placeholders, see documentation." msgstr "" -#: documents/models.py:1196 +#: documents/models.py:1207 msgid "email body" msgstr "" -#: documents/models.py:1199 +#: documents/models.py:1210 msgid "" "The body (message) of the email, can include some placeholders, see " "documentation." msgstr "" -#: documents/models.py:1205 +#: documents/models.py:1216 msgid "emails to" msgstr "" -#: documents/models.py:1208 +#: documents/models.py:1219 msgid "The destination email addresses, comma separated." msgstr "" -#: documents/models.py:1214 +#: documents/models.py:1225 msgid "include document in email" msgstr "" -#: documents/models.py:1225 +#: documents/models.py:1236 msgid "webhook url" msgstr "" -#: documents/models.py:1228 +#: documents/models.py:1239 msgid "The destination URL for the notification." msgstr "" -#: documents/models.py:1233 +#: documents/models.py:1244 msgid "use parameters" msgstr "" -#: documents/models.py:1238 +#: documents/models.py:1249 msgid "send as JSON" msgstr "" -#: documents/models.py:1242 +#: documents/models.py:1253 msgid "webhook parameters" msgstr "" -#: documents/models.py:1245 +#: documents/models.py:1256 msgid "The parameters to send with the webhook URL if body not used." msgstr "" -#: documents/models.py:1249 +#: documents/models.py:1260 msgid "webhook body" msgstr "" -#: documents/models.py:1252 +#: documents/models.py:1263 msgid "The body to send with the webhook URL if parameters not used." msgstr "" -#: documents/models.py:1256 +#: documents/models.py:1267 msgid "webhook headers" msgstr "" -#: documents/models.py:1259 +#: documents/models.py:1270 msgid "The headers to send with the webhook URL." msgstr "" -#: documents/models.py:1264 +#: documents/models.py:1275 msgid "include document in webhook" msgstr "" -#: documents/models.py:1275 +#: documents/models.py:1286 msgid "Assignment" msgstr "" -#: documents/models.py:1279 +#: documents/models.py:1290 msgid "Removal" msgstr "" -#: documents/models.py:1283 documents/templates/account/password_reset.html:15 +#: documents/models.py:1294 documents/templates/account/password_reset.html:15 msgid "Email" msgstr "" -#: documents/models.py:1287 +#: documents/models.py:1298 msgid "Webhook" msgstr "" -#: documents/models.py:1291 +#: documents/models.py:1302 msgid "Workflow Action Type" msgstr "" -#: documents/models.py:1296 documents/models.py:1529 +#: documents/models.py:1307 documents/models.py:1540 #: paperless_mail/models.py:145 msgid "order" msgstr "" -#: documents/models.py:1299 +#: documents/models.py:1310 msgid "assign title" msgstr "" -#: documents/models.py:1303 +#: documents/models.py:1314 msgid "Assign a document title, must be a Jinja2 template, see documentation." msgstr "" -#: documents/models.py:1311 paperless_mail/models.py:274 +#: documents/models.py:1322 paperless_mail/models.py:274 msgid "assign this tag" msgstr "" -#: documents/models.py:1320 paperless_mail/models.py:282 +#: documents/models.py:1331 paperless_mail/models.py:282 msgid "assign this document type" msgstr "" -#: documents/models.py:1329 paperless_mail/models.py:296 +#: documents/models.py:1340 paperless_mail/models.py:296 msgid "assign this correspondent" msgstr "" -#: documents/models.py:1338 +#: documents/models.py:1349 msgid "assign this storage path" msgstr "" -#: documents/models.py:1347 +#: documents/models.py:1358 msgid "assign this owner" msgstr "" -#: documents/models.py:1354 +#: documents/models.py:1365 msgid "grant view permissions to these users" msgstr "" -#: documents/models.py:1361 +#: documents/models.py:1372 msgid "grant view permissions to these groups" msgstr "" -#: documents/models.py:1368 +#: documents/models.py:1379 msgid "grant change permissions to these users" msgstr "" -#: documents/models.py:1375 +#: documents/models.py:1386 msgid "grant change permissions to these groups" msgstr "" -#: documents/models.py:1382 +#: documents/models.py:1393 msgid "assign these custom fields" msgstr "" -#: documents/models.py:1386 +#: documents/models.py:1397 msgid "custom field values" msgstr "" -#: documents/models.py:1390 +#: documents/models.py:1401 msgid "Optional values to assign to the custom fields." msgstr "" -#: documents/models.py:1399 +#: documents/models.py:1410 msgid "remove these tag(s)" msgstr "" -#: documents/models.py:1404 +#: documents/models.py:1415 msgid "remove all tags" msgstr "" -#: documents/models.py:1411 +#: documents/models.py:1422 msgid "remove these document type(s)" msgstr "" -#: documents/models.py:1416 +#: documents/models.py:1427 msgid "remove all document types" msgstr "" -#: documents/models.py:1423 +#: documents/models.py:1434 msgid "remove these correspondent(s)" msgstr "" -#: documents/models.py:1428 +#: documents/models.py:1439 msgid "remove all correspondents" msgstr "" -#: documents/models.py:1435 +#: documents/models.py:1446 msgid "remove these storage path(s)" msgstr "" -#: documents/models.py:1440 +#: documents/models.py:1451 msgid "remove all storage paths" msgstr "" -#: documents/models.py:1447 +#: documents/models.py:1458 msgid "remove these owner(s)" msgstr "" -#: documents/models.py:1452 +#: documents/models.py:1463 msgid "remove all owners" msgstr "" -#: documents/models.py:1459 +#: documents/models.py:1470 msgid "remove view permissions for these users" msgstr "" -#: documents/models.py:1466 +#: documents/models.py:1477 msgid "remove view permissions for these groups" msgstr "" -#: documents/models.py:1473 +#: documents/models.py:1484 msgid "remove change permissions for these users" msgstr "" -#: documents/models.py:1480 +#: documents/models.py:1491 msgid "remove change permissions for these groups" msgstr "" -#: documents/models.py:1485 +#: documents/models.py:1496 msgid "remove all permissions" msgstr "" -#: documents/models.py:1492 +#: documents/models.py:1503 msgid "remove these custom fields" msgstr "" -#: documents/models.py:1497 +#: documents/models.py:1508 msgid "remove all custom fields" msgstr "" -#: documents/models.py:1506 +#: documents/models.py:1517 msgid "email" msgstr "" -#: documents/models.py:1515 +#: documents/models.py:1526 msgid "webhook" msgstr "" -#: documents/models.py:1519 +#: documents/models.py:1530 msgid "workflow action" msgstr "" -#: documents/models.py:1520 +#: documents/models.py:1531 msgid "workflow actions" msgstr "" -#: documents/models.py:1535 +#: documents/models.py:1546 msgid "triggers" msgstr "" -#: documents/models.py:1542 +#: documents/models.py:1553 msgid "actions" msgstr "" -#: documents/models.py:1545 paperless_mail/models.py:154 +#: documents/models.py:1556 paperless_mail/models.py:154 msgid "enabled" msgstr "" -#: documents/models.py:1556 +#: documents/models.py:1567 msgid "workflow" msgstr "" -#: documents/models.py:1560 +#: documents/models.py:1571 msgid "workflow trigger type" msgstr "" -#: documents/models.py:1574 +#: documents/models.py:1585 msgid "date run" msgstr "" -#: documents/models.py:1580 +#: documents/models.py:1591 msgid "workflow run" msgstr "" -#: documents/models.py:1581 +#: documents/models.py:1592 msgid "workflow runs" msgstr ""