diff --git a/.github/workflows/issue-bot.yml b/.github/workflows/issue-bot.yml index cf2602110..1950f59b6 100644 --- a/.github/workflows/issue-bot.yml +++ b/.github/workflows/issue-bot.yml @@ -72,11 +72,9 @@ jobs: 'You are welcome to open a new issue that describes the problem you observed in your own words.' : 'This issue was automatically closed because it was not opened using our bug report form. ' + 'Issues have to be created through the form so that the details we need to investigate are included.\n\n' + - `If the problem is still there, please [open a new issue](${newIssue}) using the form — that is all it takes ` + - 'to get it looked at, and no other action is needed here.\n\n' + + `If the problem is still there, please [open a new issue](${newIssue}) using the form. No other action is needed here.\n\n` + 'If any part of your report was written by an AI tool or agent, you must say so: undisclosed AI-generated ' + - `contributions are a violation of our [Code of Conduct](${codeOfConduct}), and such reports must describe the ` + - `behavior you observed only, without code analysis or suggested fixes. See our [contributing guidelines](${contributing}).`; + `contributions are a violation of our [Code of Conduct](${codeOfConduct}).`; await github.rest.issues.createComment({ ...common, body }); await github.rest.issues.addLabels({ ...common, labels: ['ai'] }); diff --git a/.github/workflows/pr-bot.yml b/.github/workflows/pr-bot.yml index 6223c6db8..f7d69039d 100644 --- a/.github/workflows/pr-bot.yml +++ b/.github/workflows/pr-bot.yml @@ -25,6 +25,10 @@ jobs: pr-bot: name: Automated PR Bot runs-on: ubuntu-latest + # Runs after Anti-slop so the welcome comment can see whether the PR was closed + # instead of racing it. Still runs if that job fails, so labeling is not lost. + needs: Anti-slop + if: ${{ !cancelled() }} permissions: contents: read pull-requests: write @@ -99,8 +103,25 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const pr = context.payload.pull_request; - const user = pr.user.login; + const user = context.payload.pull_request.user.login; + + // Re-read the PR: Anti-slop may have closed and labeled it after the webhook + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + }); + + if (pr.state === 'closed') { + core.info('Skipping comment: PR is already closed'); + return; + } + + const labels = pr.labels.map((label) => (typeof label === 'string' ? label : label.name)); + if (labels.includes('ai')) { + core.info('Skipping comment: PR is labeled ai'); + return; + } const { data: members } = await github.rest.orgs.listMembers({ org: 'paperless-ngx', diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/dependencies.d/init-modify-user b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/dependencies.d/init-modify-user new file mode 100644 index 000000000..e69de29bb diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/dependencies.d/init-start b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/dependencies.d/init-start new file mode 100644 index 000000000..e69de29bb diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/run new file mode 100755 index 000000000..1d7ba32ec --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/run @@ -0,0 +1,58 @@ +#!/command/with-contenv /usr/bin/bash +# shellcheck shell=bash +declare -r log_prefix="[init-compile-bytecode]" + +# PYTHONDONTWRITEBYTECODE=1 is set for the whole container. This unit compiles a +# scoped set of libraries anyway, to speed up startup without bloating image size. + +# Handle the people using a read only file system +if [[ "${S6_READ_ONLY_ROOT}" == "1" ]]; then + echo "${log_prefix} S6_READ_ONLY_ROOT=1, skipping (nothing to write bytecode to)" + exit 0 +fi + +# When running as a non-root user, site-packages is still root-owned and unwritable, +# so this step would just fail loudly on every container start. Skip it. +if [[ -n "${USER_IS_NON_ROOT}" ]]; then + echo "${log_prefix} USER_IS_NON_ROOT is set, skipping (site-packages is not writable)" + exit 0 +fi + +declare -r site_packages="$(python3 -c 'import site; print(site.getsitepackages()[0])')" + +# Deliberately scoped to packages that paperless.settings/paperless/__init__.py import +# unconditionally on every manage.py invocation (Django itself, the always-loaded +# INSTALLED_APPS, and celery). This is NOT "compile everything" - the optional AI stack +# (torch, llama-index, sentence-transformers, ...) is intentionally excluded since it is +# lazy-imported and large. +declare -a scope=( + "${PAPERLESS_SRC_DIR}" + "${site_packages}/django" + "${site_packages}/celery" + "${site_packages}/kombu" + "${site_packages}/rest_framework" + "${site_packages}/django_filters" + "${site_packages}/whitenoise" + "${site_packages}/corsheaders" + "${site_packages}/django_extensions" + "${site_packages}/guardian" + "${site_packages}/allauth" + "${site_packages}/drf_spectacular" + "${site_packages}/drf_spectacular_sidecar" + "${site_packages}/treenode" + "${site_packages}/compression_middleware" +) + +declare -a existing_scope=() +for path in "${scope[@]}"; do + [[ -d "${path}" ]] && existing_scope+=("${path}") +done + +echo "${log_prefix} Compiling bytecode for: ${existing_scope[*]}" +declare -r start_seconds=${SECONDS} + +if ! PYTHONDONTWRITEBYTECODE= python3 -m compileall -q "${existing_scope[@]}"; then + echo "${log_prefix} WARNING: compileall reported errors (read-only filesystem or unwritable site-packages?); continuing without a bytecode cache" +fi + +echo "${log_prefix} Done in $((SECONDS - start_seconds))s" diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/type b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/type new file mode 100644 index 000000000..bdd22a185 --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/type @@ -0,0 +1 @@ +oneshot diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/up b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/up new file mode 100644 index 000000000..741d51531 --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-compile-bytecode/up @@ -0,0 +1 @@ +/etc/s6-overlay/s6-rc.d/init-compile-bytecode/run diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/dependencies.d/init-compile-bytecode b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/dependencies.d/init-compile-bytecode new file mode 100644 index 000000000..e69de29bb diff --git a/docs/administration.md b/docs/administration.md index 4c855b3a2..155716660 100644 --- a/docs/administration.md +++ b/docs/administration.md @@ -521,7 +521,8 @@ Pass `--recreate` to wipe the existing index before rebuilding. Use this when th index is corrupted or you want a fully clean rebuild. Pass `--if-needed` to skip the rebuild if the index is already up to date (schema -version and search language match). Safe to run on every startup or upgrade. +version, schema fingerprint and search language all match). Safe to run on every +startup or upgrade. Specify `optimize` to optimize the index. This command is regularly invoked by the task scheduler. diff --git a/docs/advanced_usage.md b/docs/advanced_usage.md index 29c427fb0..661c2d704 100644 --- a/docs/advanced_usage.md +++ b/docs/advanced_usage.md @@ -138,7 +138,9 @@ for suggested generation and embedding models. With AI enabled, Paperless-ngx can suggest a title, tags, correspondent, document type, storage path and dates by sending the document to the LLM. This is **opt-in per request** and surfaces through the "Suggest" control on the document detail page, alongside the -classic classifier-based suggestions — it does not disable them. Suggestion output +classic classifier-based suggestions — it does not disable them. Suggestions are requested +automatically when you open a document that carries an inbox tag unless "Automatically request +suggestions for inbox documents" under Settings > Documents is disabled. Suggestion output language can be steered with [`PAPERLESS_AI_LLM_OUTPUT_LANGUAGE`](configuration.md#PAPERLESS_AI_LLM_OUTPUT_LANGUAGE) (otherwise it follows the user's UI language). diff --git a/docs/configuration.md b/docs/configuration.md index 37a552f1a..0068a325d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1200,6 +1200,23 @@ still perform some basic text pre-processing before matching. Defaults to true, enabling the feature. +#### [`PAPERLESS_CLASSIFIER_MATCH_THRESHOLD=`](#PAPERLESS_CLASSIFIER_MATCH_THRESHOLD) {#PAPERLESS_CLASSIFIER_MATCH_THRESHOLD} + +: Sets the minimum confidence score (0.0-1.0) required for the automatic +classifier to assign a correspondent, document type, or storage path to a +document. Predictions below this threshold are discarded and the field is +left unassigned, preventing low-confidence guesses from being applied. + + Defaults to 0.6. + +#### [`PAPERLESS_MATCH_REGEX_TIMEOUT_SECONDS=`](#PAPERLESS_MATCH_REGEX_TIMEOUT_SECONDS) {#PAPERLESS_MATCH_REGEX_TIMEOUT_SECONDS} + +: Sets the timeout, in seconds, for regular expression matching. Increase this +value if date parsing or user-defined matching rules time out when processing +long documents, especially on slower hardware. + + Defaults to 0.1 seconds. + #### [`PAPERLESS_DATE_PARSER_LANGUAGES=`](#PAPERLESS_DATE_PARSER_LANGUAGES) {#PAPERLESS_DATE_PARSER_LANGUAGES} : Specifies which language Paperless should use when parsing dates from documents. diff --git a/docs/usage.md b/docs/usage.md index 805e15718..12cdaa921 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -317,6 +317,8 @@ a "document already exists" message. Paperless-ngx can suggest tags, correspondents, document types and storage paths for documents based on the content of the document. This is done using a (non-LLM) machine learning model that is trained on the documents in your database. The suggestions are shown in the document detail page and can be accepted or rejected by the user. +Suggestions are requested automatically when you open a document that still has an inbox tag. To only request them by pressing the "Suggest" button instead, turn off "Automatically request suggestions for inbox documents" under Settings > Documents. + ## AI Features Paperless-ngx includes several features that use AI to enhance the document management experience. These features are optional and can be enabled or disabled in the settings. If you are using the AI features, you may want to also enable the "LLM index" feature, which supports Retrieval-Augmented Generation (RAG) designed to improve the quality of AI responses. The LLM index feature is not enabled by default and requires additional configuration. @@ -684,7 +686,8 @@ It requires [AI features](configuration.md#ai) to be enabled. You can specify: never replace the document's existing tags. The action works with every trigger **except Consumption Started**, because suggestions are made from -the document's text, which does not exist until after the document has been processed. +the document's text, which does not exist until after the document has been processed. Documents whose +processed text is empty or contains only whitespace are skipped. Because the query to the AI service is slow, the action is queued and runs in the background rather than as part of the workflow run itself. The document is updated once the suggestions come back. @@ -924,52 +927,105 @@ typed in the search bar. A few things to know about how matching works: Paperless also offers advanced search syntax if you want to drill down further. -Matching documents with logical expressions: +#### Combining terms ``` shopname AND (product1 OR product2) +invoice NOT draft +"quick brown fox" ``` -Matching specific tags, correspondents or types: +- `AND`, `OR` and `NOT` must be written in capitals. Parentheses group terms. +- Terms with no operator between them are combined with `AND`. +- Quotes match an exact phrase, with the words in that order. + +!!! warning + + A leading `-` does **not** exclude a term. `invoice -secret` finds documents containing both words. Use `invoice NOT secret` instead. + +#### Searching by field + +Put a field name and a colon in front of a value to search only that field: ``` type:invoice tag:unpaid -correspondent:university certificate +correspondent:"acme corp" +tag:bills,unpaid +asn:[50 to 150] +checksum:9f86d081* ``` -Matching dates: +| Field | Searches | +| ------------------------- | ---------------------------------------- | +| `title` | Title | +| `content` | Text content | +| `correspondent` | Correspondent | +| `document_type` or `type` | Document type | +| `storage_path` or `path` | Storage path | +| `tag` | Tags | +| `original_filename` | File name the document was consumed with | +| `asn` | Archive serial number | +| `page_count` | Number of pages | +| `num_notes` | Number of notes | +| `checksum` | Checksum of the original file | +| `created` | Created date | +| `added` | When the document was added to paperless | +| `modified` | When the document was last modified | + +- A field applies only to the word right after it. Quote multi-word values: `correspondent:"acme corp"`. +- A comma-separated `tag` list requires every listed tag, so `tag:bills,unpaid` only matches documents tagged with both. +- `asn`, `page_count` and `num_notes` are numbers. They accept ranges like `asn:[50 to 150]`, but not wildcards. +- `checksum` only matches the complete checksum, in lowercase. To search by its first few characters, add a wildcard: `checksum:9f86d081*`. +- `created`, `added` and `modified` take the values described in [Searching by date](#searching-by-date). +- Custom fields and notes have their own syntax, described [below](#searching-custom-fields). + +#### Wildcards + +``` +invoice* +title:Invoice* +20[12]? +20[!0]? +``` + +- `*` matches any number of characters, and `?` matches exactly one. +- `[...]` matches one character from a set or range, and `[!...]` matches one character not in it. `20[12]?` matches 2010 to 2029. +- Brackets only act as a wildcard when the value also contains a `*` or `?`. Otherwise they are searched as ordinary text. The exception is a single-character range such as `title:200[1-9]`, which is rejected with an error. Add a wildcard to use it as a pattern: `title:200[1-9]*`. + +!!! note + + When a [stemmer is available](configuration.md#PAPERLESS_SEARCH_LANGUAGE) for your search language, words are indexed by their stem, so `copy*` also finds "copies". A prefix that runs past the stem can find nothing: `universit*` misses "university", which is stored as `univers`. If a wildcard finds nothing, try a shorter prefix, such as `univers*`. + +#### Searching by date ``` -created:[2005 to 2009] added:yesterday -modified:today +modified:"previous month" +created:[2005 to 2009] +added:[-1 week to now] ``` -Matching inexact words: +These keywords each cover a whole period, and work with or without quotes: `today`, `yesterday`, `tomorrow`, `previous week`, `this month`, `previous month`, `previous quarter`, `this year`, `previous year`. -``` -produ*name -``` +Other supported forms: -Matching natural date keywords: +| Example | Matches | Quotes | +| ------------------------------------------------------- | ------------------------------ | -------- | +| `created:2005`, `created:2005-01`, `created:2005-03-04` | That year, month or day | Optional | +| `added:january` | That month in the current year | Optional | +| `added:"next monday"`, `added:"last monday"` | That day | Required | +| `added:"12 december 2019"` | That day | Required | +| `added:"2005-01-01T00:00:00Z"` | That exact time | Required | -``` -added:today -modified:yesterday -created:"previous week" -added:"previous month" -modified:"this year" -``` +Ranges take two bounds in square brackets, for example `created:[2005 to 2009]`. A bound can be any of the forms above, or a relative time like `-1 week`, `now-7d` or `now`. Bounds don't need quotes. If you do quote one, use single quotes (`added:['-1 week' to now]`), because double quotes are rejected. -Supported date keywords: `today`, `yesterday`, `previous week`, -`this month`, `previous month`, `this year`, `previous year`, -`previous quarter`. +!!! warning + + `now`, `noon`, `midnight` and relative times like `-1 week` only work as range bounds. On their own they mean a single instant, so `added:"-1 week"` finds nothing. Use `added:[-1 week to now]` instead. A bare weekday (`monday`) and spellings like `3 days ago` or `this week` are not supported at all. #### Searching custom fields -Custom field names and values are included in the full-text index, but they -are not searched by a plain, unqualified query. Use the advanced search syntax -to search by field name or value: +Custom field names and values are included in the full-text index, but a plain search without a field name does not look at them. Use the advanced search syntax to search by field name or value: ``` custom_fields.value:policy @@ -980,10 +1036,9 @@ custom_fields.name:Insurance custom_fields.value:policy - `custom_fields.value` matches against the value of any custom field. - `custom_fields.name` matches the name of the field (use quotes for multi-word names). - Combine both to find documents where a specific named field contains a specific value. +- The bare `custom_fields:` prefix is shorthand for `custom_fields.value:`. -Because separators are stripped during indexing, individual parts of formatted -codes are searchable on their own. A value stored as `A-1312/99.50` produces the -tokens `a`, `1312`, `99`, `50` — each searchable independently: +Because separators are stripped during indexing, each part of a formatted code can be searched on its own. A value stored as `A-1312/99.50` is indexed as `a`, `1312`, `99` and `50`: ``` custom_fields.value:1312 @@ -992,14 +1047,11 @@ custom_fields.name:"Contract Number" custom_fields.value:1312 !!! note - Custom date fields do not support relative date syntax (e.g. `[now to 2 weeks]`). - For date ranges on custom date fields, use the document list filters in the web UI. + Custom date fields do not support relative date syntax such as `[now to 2 weeks]`. For date ranges on custom date fields, use the document list filters in the web UI. #### Searching notes -Notes are included in the full-text index, but they are not searched by a -plain, unqualified query. Use the advanced search syntax to search by note -author or content: +Notes are included in the full-text index, but a plain search without a field name does not look at them. Use the advanced search syntax to search by note author or content: ``` notes.user:alice @@ -1007,15 +1059,13 @@ notes.note:reminder notes.user:alice notes.note:insurance ``` -All of these constructs can be combined as you see fit. If you want to -learn more about the query language used by paperless, see the -[Tantivy query language documentation](https://docs.rs/tantivy/latest/tantivy/query/struct.QueryParser.html). +The bare `notes:` prefix is shorthand for `notes.note:`. + +All of these can be combined. Syntax not described here may not work as expected, and an unknown field name is searched as ordinary text. !!! note - Fuzzy (approximate) matching can be enabled by setting - [`PAPERLESS_ADVANCED_FUZZY_SEARCH_THRESHOLD`](configuration.md#PAPERLESS_ADVANCED_FUZZY_SEARCH_THRESHOLD). - When enabled, paperless will include near-miss results ranked below exact matches. + Fuzzy (approximate) matching can be enabled by setting [`PAPERLESS_ADVANCED_FUZZY_SEARCH_THRESHOLD`](configuration.md#PAPERLESS_ADVANCED_FUZZY_SEARCH_THRESHOLD). When enabled, paperless also includes near-miss results, ranked below exact matches. ## Keyboard shortcuts / hotkeys diff --git a/pyproject.toml b/pyproject.toml index 8364aacf0..ab6cd1191 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,21 +32,21 @@ dependencies = [ "django-cors-headers~=4.9.0", "django-extensions~=4.1", "django-filter~=25.1", - "django-guardian~=3.3.3", + "django-guardian>=3.3.3,<3.5", "django-multiselectfield~=1.0.1", "django-rich~=2.2.0", "django-soft-delete~=1.0.18", "django-treenode>=0.24", "djangorestframework~=3.16", "drf-spectacular~=0.30", - "drf-spectacular-sidecar~=2026.7.1", + "drf-spectacular-sidecar>=2026.7.1,<2026.9", "drf-writable-nested~=0.7.1", "filelock~=3.32.0", "flower>=2.0.1,<2.2", "gotenberg-client[httpx]~=1.0", "httpx-oauth~=0.17", "ijson>=3.5.1", - "imap-tools~=1.14.0", + "imap-tools>=1.14,<1.16", "jinja2~=3.1.6", "langdetect~=1.0.9", "llama-index-core>=0.14.23", @@ -56,7 +56,7 @@ dependencies = [ "llama-index-llms-ollama>=0.9.1", "llama-index-llms-openai-like>=0.7.1", "nltk~=3.10.0", - "ocrmypdf>=17.7,<17.11", + "ocrmypdf>=17.7,<17.12", "openai>=2.48", "pathvalidate~=3.3.1", "pdf2image~=1.17.0", @@ -77,6 +77,7 @@ dependencies = [ "torch~=2.13.0", "watchfiles>=1.2", "whitenoise~=6.11", + "whoosh-compat[tantivy]==0.2", "zxing-cpp~=3.1.0", ] [project.optional-dependencies] @@ -103,17 +104,17 @@ docs = [ "zensical>=0.0.51", ] lint = [ - "prek~=0.4.11", + "prek>=0.4.11,<0.6", "ruff~=0.16.1", ] testing = [ "daphne", "factory-boy~=3.3.1", - "faker~=40.36.0", + "faker>=40.36,<40.38", "imagehash", "pytest~=9.1.1", "pytest-cov~=7.1.0", - "pytest-django~=4.12.0", + "pytest-django>=4.12,<4.15", "pytest-env~=1.7.0", "pytest-httpx", "pytest-mock~=3.15.1", diff --git a/src-ui/angular.json b/src-ui/angular.json index 9e715a809..c3801947d 100644 --- a/src-ui/angular.json +++ b/src-ui/angular.json @@ -71,8 +71,10 @@ "tsConfig": "tsconfig.app.json", "localize": true, "assets": [ - "src/favicon.ico", "src/apple-touch-icon.png", + "src/icon-192.png", + "src/icon-512.png", + "src/icon-512-maskable.png", "src/assets", "src/manifest.webmanifest", { diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf index e0f550a84..ad5855428 100644 --- a/src-ui/messages.xlf +++ b/src-ui/messages.xlf @@ -294,6 +294,10 @@ src/app/app.component.ts 139 + + src/app/components/admin/settings/settings.component.ts + 111 + src/app/components/app-frame/app-frame.component.html 91 @@ -302,6 +306,10 @@ src/app/components/app-frame/app-frame.component.html 93 + + src/app/components/app-frame/app-frame.component.html + 96 + src/app/components/dashboard/dashboard.component.html 1 @@ -315,19 +323,19 @@ src/app/components/admin/settings/settings.component.html - 195,196 + 211,212 src/app/components/admin/settings/settings.component.html - 199,200 + 215,216 src/app/components/app-frame/app-frame.component.html - 100 + 103 src/app/components/app-frame/app-frame.component.html - 102 + 105 src/app/components/common/share-link-bundle-dialog/share-link-bundle-dialog.component.html @@ -378,11 +386,11 @@ src/app/components/app-frame/app-frame.component.html - 282 + 294 src/app/components/app-frame/app-frame.component.html - 284 + 296 @@ -501,26 +509,54 @@ 30 - - Reset - - src/app/components/admin/config/config.component.html - 34 - + + This value overrides , which is set outside Paperless. src/app/components/admin/config/config.component.html 35 + + + is set outside Paperless. Enter a value here to override it. + + src/app/components/admin/config/config.component.html + 37 + + + + Use the externally configured value + + src/app/components/admin/config/config.component.html + 42 + + + + Reset to external + + src/app/components/admin/config/config.component.html + 43 + + + + Reset + + src/app/components/admin/config/config.component.html + 46 + + + src/app/components/admin/config/config.component.html + 47 + src/app/components/admin/settings/settings.component.html - 138 + 154 Enable src/app/components/admin/config/config.component.html - 43 + 56 src/app/components/common/profile-edit-dialog/profile-edit-dialog.component.html @@ -531,11 +567,11 @@ Cancel src/app/components/admin/config/config.component.html - 67,68 + 80,81 src/app/components/admin/settings/settings.component.html - 401,402 + 423,424 src/app/components/common/confirm-dialog/confirm-dialog.component.ts @@ -610,11 +646,11 @@ Save src/app/components/admin/config/config.component.html - 70,71 + 83,84 src/app/components/admin/settings/settings.component.html - 402,403 + 424,425 src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html @@ -681,42 +717,42 @@ Error retrieving config src/app/components/admin/config/config.component.ts - 117 + 118 Invalid JSON src/app/components/admin/config/config.component.ts - 143 + 144 Configuration updated src/app/components/admin/config/config.component.ts - 187 + 193 An error occurred updating configuration src/app/components/admin/config/config.component.ts - 192 + 198 File successfully updated src/app/components/admin/config/config.component.ts - 214 + 220 An error occurred uploading file src/app/components/admin/config/config.component.ts - 219 + 225 @@ -727,11 +763,11 @@ src/app/components/app-frame/app-frame.component.html - 319 + 331 src/app/components/app-frame/app-frame.component.html - 321 + 333 @@ -1001,46 +1037,53 @@ 113 + + Sidebar items to show: + + src/app/components/admin/settings/settings.component.html + 115,116 + + Dark mode src/app/components/admin/settings/settings.component.html - 120,121 + 136,137 Use system settings src/app/components/admin/settings/settings.component.html - 123 + 139 Enable dark mode src/app/components/admin/settings/settings.component.html - 124 + 140 Invert thumbnails in dark mode src/app/components/admin/settings/settings.component.html - 125 + 141 Theme Color src/app/components/admin/settings/settings.component.html - 131,132 + 147,148 Global search src/app/components/admin/settings/settings.component.html - 144,145 + 160,161 src/app/components/app-frame/global-search/global-search.component.ts @@ -1051,28 +1094,28 @@ Do not include advanced search results src/app/components/admin/settings/settings.component.html - 147 + 163 Full search links to src/app/components/admin/settings/settings.component.html - 153,154 + 169,170 Title and content search src/app/components/admin/settings/settings.component.html - 157,158 + 173,174 Advanced search src/app/components/admin/settings/settings.component.html - 158,159 + 174,175 src/app/components/app-frame/global-search/global-search.component.html @@ -1080,28 +1123,28 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts - 206 + 210 Update checking src/app/components/admin/settings/settings.component.html - 163,164 + 179,180 Enable update checking src/app/components/admin/settings/settings.component.html - 166 + 182 What's this? src/app/components/admin/settings/settings.component.html - 167 + 183 src/app/components/common/page-header/page-header.component.html @@ -1120,29 +1163,37 @@ Update checking works by pinging the public GitHub API for the latest release to determine whether a new version is available. Actual updating of the app must still be performed manually. src/app/components/admin/settings/settings.component.html - 172 + 188 No tracking data is collected by the app in any way. src/app/components/admin/settings/settings.component.html - 175,176 + 191,192 Saved Views src/app/components/admin/settings/settings.component.html - 181,182 + 197,198 + + + src/app/components/admin/settings/settings.component.ts + 112 src/app/components/app-frame/app-frame.component.html - 242 + 245 src/app/components/app-frame/app-frame.component.html - 244 + 247 + + + src/app/components/app-frame/app-frame.component.html + 250 src/app/components/manage/saved-views/saved-views.component.html @@ -1153,126 +1204,140 @@ Show warning when closing saved views with unsaved changes src/app/components/admin/settings/settings.component.html - 184 + 200 Show document counts in sidebar saved views src/app/components/admin/settings/settings.component.html - 185 + 201 Items per page src/app/components/admin/settings/settings.component.html - 202,203 + 218,219 Document editing src/app/components/admin/settings/settings.component.html - 214,215 + 230,231 Use PDF viewer provided by the browser src/app/components/admin/settings/settings.component.html - 217 + 233 This is usually faster for displaying large PDF documents, but it might not work on some browsers. src/app/components/admin/settings/settings.component.html - 217 + 233 Default zoom src/app/components/admin/settings/settings.component.html - 223,224 + 239,240 Fit width src/app/components/admin/settings/settings.component.html - 227,228 + 243,244 Fit page src/app/components/admin/settings/settings.component.html - 228,229 + 244,245 Only applies to the Paperless-ngx PDF viewer. src/app/components/admin/settings/settings.component.html - 230,231 + 246,247 Automatically remove inbox tag(s) on save src/app/components/admin/settings/settings.component.html - 236 + 252 + + + + Automatically request suggestions for inbox documents + + src/app/components/admin/settings/settings.component.html + 258 + + + + If un-checked, suggestions must be requested via the Suggest button. + + src/app/components/admin/settings/settings.component.html + 258 Show document thumbnail during loading src/app/components/admin/settings/settings.component.html - 242 + 264 Built-in fields to show: src/app/components/admin/settings/settings.component.html - 248,249 + 270,271 Uncheck fields to hide them on the document details page. src/app/components/admin/settings/settings.component.html - 260,261 + 282,283 Bulk editing src/app/components/admin/settings/settings.component.html - 266,267 + 288,289 Show confirmation dialogs src/app/components/admin/settings/settings.component.html - 269 + 291 Apply on close src/app/components/admin/settings/settings.component.html - 270 + 292 PDF Editor src/app/components/admin/settings/settings.component.html - 274,275 + 296,297 src/app/components/document-detail/document-detail.component.html @@ -1280,21 +1345,21 @@ src/app/components/document-detail/document-detail.component.ts - 1800 + 1865 Default editing mode src/app/components/admin/settings/settings.component.html - 277,278 + 299,300 Create new document(s) src/app/components/admin/settings/settings.component.html - 281,282 + 303,304 src/app/components/common/pdf-editor/pdf-editor.component.html @@ -1305,7 +1370,7 @@ Add document version src/app/components/admin/settings/settings.component.html - 282,283 + 304,305 src/app/components/common/pdf-editor/pdf-editor.component.html @@ -1316,7 +1381,7 @@ Notes src/app/components/admin/settings/settings.component.html - 287,288 + 309,310 src/app/components/document-list/document-list.component.html @@ -1335,14 +1400,14 @@ Enable notes src/app/components/admin/settings/settings.component.html - 290 + 312 Permissions src/app/components/admin/settings/settings.component.html - 299,300 + 321,322 src/app/components/common/edit-dialog/group-edit-dialog/group-edit-dialog.component.html @@ -1397,28 +1462,28 @@ Default Permissions src/app/components/admin/settings/settings.component.html - 302,304 + 324,326 Settings apply to this user account for objects (Tags, Mail Rules, etc.) created via the web UI. These settings do not apply to documents. src/app/components/admin/settings/settings.component.html - 307 + 329 Default Owner src/app/components/admin/settings/settings.component.html - 313,314 + 335,336 Objects without an owner can be viewed and edited by all users src/app/components/admin/settings/settings.component.html - 317,318 + 339,340 src/app/components/common/input/permissions/permissions-form/permissions-form.component.html @@ -1429,18 +1494,18 @@ Default View Permissions src/app/components/admin/settings/settings.component.html - 322,323 + 344,345 Users: src/app/components/admin/settings/settings.component.html - 327,328 + 349,350 src/app/components/admin/settings/settings.component.html - 354,355 + 376,377 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html @@ -1471,11 +1536,11 @@ Groups: src/app/components/admin/settings/settings.component.html - 337,338 + 359,360 src/app/components/admin/settings/settings.component.html - 364,365 + 386,387 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html @@ -1506,14 +1571,14 @@ Default Edit Permissions src/app/components/admin/settings/settings.component.html - 349,350 + 371,372 Edit permissions also grant viewing permissions src/app/components/admin/settings/settings.component.html - 373,374 + 395,396 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html @@ -1532,7 +1597,7 @@ Notifications src/app/components/admin/settings/settings.component.html - 381,382 + 403,404 src/app/components/app-frame/toasts-dropdown/toasts-dropdown.component.html @@ -1547,63 +1612,63 @@ Document processing src/app/components/admin/settings/settings.component.html - 384,386 + 406,408 Show notifications when new documents are detected src/app/components/admin/settings/settings.component.html - 388 + 410 Show notifications when document processing completes successfully src/app/components/admin/settings/settings.component.html - 389 + 411 Show notifications when document processing fails src/app/components/admin/settings/settings.component.html - 390 + 412 Suppress notifications on dashboard src/app/components/admin/settings/settings.component.html - 391 + 413 This will suppress all messages about document processing status on the dashboard. src/app/components/admin/settings/settings.component.html - 391 + 413 Use system language src/app/components/admin/settings/settings.component.ts - 80 + 85 Use date format of display language src/app/components/admin/settings/settings.component.ts - 83 + 88 Archive serial number src/app/components/admin/settings/settings.component.ts - 97 + 102 src/app/components/document-detail/document-detail.component.html @@ -1614,11 +1679,11 @@ Correspondent src/app/components/admin/settings/settings.component.ts - 99 + 104 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 173 + 174 src/app/components/document-detail/document-detail.component.html @@ -1649,11 +1714,11 @@ Document type src/app/components/admin/settings/settings.component.ts - 100 + 105 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 177 + 178 src/app/components/document-detail/document-detail.component.html @@ -1684,11 +1749,11 @@ Storage path src/app/components/admin/settings/settings.component.ts - 101 + 106 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 181 + 182 src/app/components/document-detail/document-detail.component.html @@ -1715,15 +1780,15 @@ Tags src/app/components/admin/settings/settings.component.ts - 102 + 107 src/app/components/app-frame/app-frame.component.html - 213 + 216 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 169 + 170 src/app/components/common/input/tags/tags.component.ts @@ -1762,66 +1827,147 @@ 84 + + Workflows + + src/app/components/admin/settings/settings.component.ts + 113 + + + src/app/components/app-frame/app-frame.component.html + 257 + + + src/app/components/app-frame/app-frame.component.html + 259 + + + src/app/components/app-frame/app-frame.component.html + 262 + + + src/app/components/manage/workflows/workflows.component.html + 2,3 + + + + Mail + + src/app/components/admin/settings/settings.component.ts + 114 + + + src/app/components/app-frame/app-frame.component.html + 268 + + + src/app/components/app-frame/app-frame.component.html + 270 + + + src/app/components/app-frame/app-frame.component.html + 273 + + + + Documentation + + src/app/components/admin/settings/settings.component.ts + 115 + + + src/app/components/app-frame/app-frame.component.html + 66 + + + src/app/components/app-frame/app-frame.component.html + 339,340 + + + src/app/components/app-frame/app-frame.component.html + 342 + + + src/app/components/app-frame/app-frame.component.html + 345 + + Error retrieving users src/app/components/admin/settings/settings.component.ts - 255 + 279 src/app/components/admin/users-groups/users-groups.component.ts 75 + + src/app/components/common/input/permissions/permissions-user/permissions-user.component.ts + 35 + + + src/app/components/common/permissions-dialog/permissions-dialog.component.ts + 45 + Error retrieving groups src/app/components/admin/settings/settings.component.ts - 274 + 298 src/app/components/admin/users-groups/users-groups.component.ts 89 + + src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts + 48 + + + src/app/components/common/input/permissions/permissions-group/permissions-group.component.ts + 35 + Settings were saved successfully. src/app/components/admin/settings/settings.component.ts - 591 + 650 Settings were saved successfully. Reload is required to apply some changes. src/app/components/admin/settings/settings.component.ts - 595 + 654 Reload now src/app/components/admin/settings/settings.component.ts - 596 + 655 An error occurred while saving settings. src/app/components/admin/settings/settings.component.ts - 606 + 665 src/app/components/app-frame/app-frame.component.ts - 188 + 197 src/app/components/app-frame/app-frame.component.ts - 289 + 302 src/app/components/app-frame/app-frame.component.ts - 318 + 331 @@ -1832,11 +1978,11 @@ src/app/components/app-frame/app-frame.component.html - 305 + 317 src/app/components/app-frame/app-frame.component.html - 307 + 319 @@ -1922,7 +2068,7 @@ src/app/components/admin/tasks/tasks.component.ts - 215 + 219 @@ -1933,7 +2079,7 @@ src/app/components/admin/tasks/tasks.component.ts - 227 + 231 @@ -2099,7 +2245,7 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 96 + 97 src/app/components/common/share-link-bundle-manage-dialog/share-link-bundle-manage-dialog.component.html @@ -2269,15 +2415,15 @@ src/app/components/admin/tasks/tasks.component.ts - 317 + 321 src/app/components/admin/tasks/tasks.component.ts - 351 + 355 src/app/components/document-detail/document-detail.component.ts - 666 + 690 src/app/components/document-detail/document-version-dropdown/document-version-dropdown.component.html @@ -2414,7 +2560,7 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 81 + 82 @@ -2466,143 +2612,150 @@ 100 + + Apply AI Suggestions + + src/app/components/admin/tasks/tasks.component.ts + 104 + + Scheduled src/app/components/admin/tasks/tasks.component.ts - 110 + 114 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 123 + 124 Web UI src/app/components/admin/tasks/tasks.component.ts - 112 + 116 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 85 + 86 API Upload src/app/components/admin/tasks/tasks.component.ts - 115 + 119 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 77 + 78 Folder Consume src/app/components/admin/tasks/tasks.component.ts - 119 + 123 Email Consume src/app/components/admin/tasks/tasks.component.ts - 123 + 127 System src/app/components/admin/tasks/tasks.component.ts - 125 + 129 Manual src/app/components/admin/tasks/tasks.component.ts - 126 + 130 Dismiss selected src/app/components/admin/tasks/tasks.component.ts - 239 + 243 Dismiss visible src/app/components/admin/tasks/tasks.component.ts - 240 + 244 Confirm Dismiss src/app/components/admin/tasks/tasks.component.ts - 314 + 318 Dismiss tasks? src/app/components/admin/tasks/tasks.component.ts - 315 + 319 Error dismissing tasks src/app/components/admin/tasks/tasks.component.ts - 326 + 330 src/app/components/admin/tasks/tasks.component.ts - 360 + 364 Error dismissing task src/app/components/admin/tasks/tasks.component.ts - 338 + 342 Confirm Dismiss All src/app/components/admin/tasks/tasks.component.ts - 348 + 352 Dismiss all tasks? src/app/components/admin/tasks/tasks.component.ts - 349 + 353 Success. New document id created src/app/components/admin/tasks/tasks.component.ts - 408 + 412 Duplicate of document # src/app/components/admin/tasks/tasks.component.ts - 418 + 422 src/app/components/admin/tasks/tasks.component.ts - 452 + 456 @@ -2613,11 +2766,11 @@ src/app/components/app-frame/app-frame.component.html - 266 + 278 src/app/components/app-frame/app-frame.component.html - 268 + 280 @@ -2713,7 +2866,7 @@ src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 88 + 89 src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html @@ -2974,11 +3127,11 @@ src/app/components/app-frame/app-frame.component.html - 296 + 308 src/app/components/app-frame/app-frame.component.html - 298 + 310 @@ -3184,11 +3337,11 @@ src/app/components/document-detail/document-detail.component.ts - 1414 + 1479 src/app/components/document-detail/document-detail.component.ts - 1801 + 1866 src/app/components/document-list/bulk-editor/bulk-editor.component.ts @@ -3318,73 +3471,58 @@ 61 - - Documentation - - src/app/components/app-frame/app-frame.component.html - 66 - - - src/app/components/app-frame/app-frame.component.html - 327,328 - - - src/app/components/app-frame/app-frame.component.html - 330 - - Saved views src/app/components/app-frame/app-frame.component.html - 110,111 + 113,114 src/app/components/app-frame/app-frame.component.html - 140,141 + 143,144 Open documents src/app/components/app-frame/app-frame.component.html - 149,150 + 152,153 Close all src/app/components/app-frame/app-frame.component.html - 171 + 174 src/app/components/app-frame/app-frame.component.html - 173 + 176 Manage src/app/components/app-frame/app-frame.component.html - 182,183 + 185,186 Attributes src/app/components/app-frame/app-frame.component.html - 190 + 193 src/app/components/app-frame/app-frame.component.html - 192 + 195 Correspondents src/app/components/app-frame/app-frame.component.html - 218 + 221 src/app/components/common/suggestions-dropdown/suggestions-dropdown.component.html @@ -3403,7 +3541,7 @@ Document types src/app/components/app-frame/app-frame.component.html - 223 + 226 src/app/components/manage/document-attributes/document-attributes.component.ts @@ -3414,7 +3552,7 @@ Storage paths src/app/components/app-frame/app-frame.component.html - 228 + 231 src/app/components/manage/document-attributes/document-attributes.component.ts @@ -3425,7 +3563,7 @@ Custom fields src/app/components/app-frame/app-frame.component.html - 233 + 236 src/app/components/document-list/bulk-editor/bulk-editor.component.html @@ -3440,118 +3578,92 @@ 125 - - Workflows - - src/app/components/app-frame/app-frame.component.html - 251 - - - src/app/components/app-frame/app-frame.component.html - 253 - - - src/app/components/manage/workflows/workflows.component.html - 2,3 - - - - Mail - - src/app/components/app-frame/app-frame.component.html - 259 - - - src/app/components/app-frame/app-frame.component.html - 261 - - Administration src/app/components/app-frame/app-frame.component.html - 276,277 + 288,289 Configuration src/app/components/app-frame/app-frame.component.html - 289 + 301 src/app/components/app-frame/app-frame.component.html - 291 + 303 GitHub src/app/components/app-frame/app-frame.component.html - 337 + 352 is available. src/app/components/app-frame/app-frame.component.html - 347 + 362 Click to view. src/app/components/app-frame/app-frame.component.html - 347 + 362 Paperless-ngx can automatically check for updates src/app/components/app-frame/app-frame.component.html - 351 + 366 How does this work? src/app/components/app-frame/app-frame.component.html - 359 + 374 Update available src/app/components/app-frame/app-frame.component.html - 371 + 386 Configure update checking src/app/components/app-frame/app-frame.component.html - 376 + 391 Sidebar views updated src/app/components/app-frame/app-frame.component.ts - 454 + 467 Error updating sidebar views src/app/components/app-frame/app-frame.component.ts - 457 + 470 An error occurred while saving update checking settings. src/app/components/app-frame/app-frame.component.ts - 478 + 491 @@ -3830,7 +3942,7 @@ src/app/components/document-detail/document-detail.component.ts - 1367 + 1432 src/app/components/document-list/bulk-editor/bulk-editor.component.ts @@ -3974,7 +4086,7 @@ src/app/components/document-detail/document-detail.component.ts - 1854 + 1919 @@ -3985,7 +4097,7 @@ src/app/components/document-detail/document-detail.component.ts - 1855 + 1920 @@ -3996,7 +4108,7 @@ src/app/components/document-detail/document-detail.component.ts - 1856 + 1921 @@ -4348,7 +4460,7 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 92 + 93 src/app/components/document-list/document-list.component.html @@ -5047,158 +5159,183 @@ Only process attachments src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 39 + 40 src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 50 + 51 Process all files, including 'inline' attachments src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 43 + 44 Process message as .eml src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 54 + 55 Process message as .eml and attachments separately src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 58 + 59 System default src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 65 + 66 Text, then HTML src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 69 + 70 HTML, then text src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 73 + 74 HTML only src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 77 + 78 Text only src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 81 + 82 Move to specified folder src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 92 + 93 Mark as read, don't process read mails src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 96 + 97 Flag the mail, don't process flagged mails src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 100 + 101 Tag the mail with specified tag, don't process tagged mails src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 104 + 105 Use subject as title src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 111 + 112 Use attachment filename as title src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 115 + 116 Do not assign title from this rule src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 119 + 120 Do not assign a correspondent src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 126 + 127 Use mail address src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 130 + 131 Use name (or mail address if not available) src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 134 + 135 Use correspondent selected below src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 138 + 139 + + + + Error retrieving mail accounts + + src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts + 169 + + + src/app/components/manage/mail/mail.component.ts + 110 + + + + Error retrieving correspondents + + src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts + 182 + + + + Error retrieving document types + + src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts + 195 Create new mail rule src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 183 + 212 Edit mail rule src/app/components/common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component.ts - 187 + 216 @@ -5338,7 +5475,7 @@ src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 138 + 139 src/app/components/common/profile-edit-dialog/profile-edit-dialog.component.html @@ -5448,32 +5585,32 @@ Create new user account src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts - 68 + 74 Edit user account src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts - 72 + 78 Totp deactivated src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts - 129 + 135 Totp deactivation failed src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts - 132 + 138 src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts - 137 + 143 @@ -6030,14 +6167,14 @@ Consume Folder src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 73 + 74 Modified src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 100 + 101 src/app/data/document.ts @@ -6048,67 +6185,67 @@ Custom Field src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 104 + 105 Consumption Started src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 111 + 112 Document Added src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 115 + 116 Document Updated src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 119 + 120 Assignment src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 130 + 131 Removal src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 134 + 135 Webhook src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 142 + 143 Password removal src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 146 + 147 Move to trash src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 150 + 151 src/app/components/document-detail/document-detail.component.ts - 1371 + 1436 src/app/components/document-list/bulk-editor/bulk-editor.component.ts @@ -6119,7 +6256,7 @@ Remote OCR src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 154 + 155 src/app/data/paperless-config.ts @@ -6130,14 +6267,14 @@ Apply AI suggestions src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 158 + 159 Title src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 165 + 166 src/app/components/document-detail/document-detail.component.html @@ -6149,7 +6286,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts - 197 + 201 src/app/data/document.ts @@ -6164,112 +6301,119 @@ Created date src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 185 + 186 Has any of these tags src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 254 + 255 Has all of these tags src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 261 + 262 Does not have these tags src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 268 + 269 Has any of these correspondents src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 275 + 276 Has correspondent src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 283 + 284 Does not have correspondents src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 291 + 292 Has document type src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 299 + 300 Has any of these document types src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 307 + 308 Does not have document types src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 315 + 316 Has storage path src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 323 + 324 Has any of these storage paths src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 331 + 332 Does not have storage paths src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 339 + 340 Matches custom field query src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 347 + 348 + + + + Some workflow options could not be loaded. + + src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts + 570 Create new workflow src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 563 + 592 Edit workflow src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts - 567 + 596 @@ -6822,28 +6966,28 @@ Set permissions src/app/components/common/permissions-dialog/permissions-dialog.component.ts - 43 + 51 Edit permissions for src/app/components/common/permissions-dialog/permissions-dialog.component.ts - 54 + 62 Existing owner, user and group permissions will be merged with these settings. src/app/components/common/permissions-dialog/permissions-dialog.component.ts - 93 + 101 Any and all existing owner, user and group permissions will be replaced. src/app/components/common/permissions-dialog/permissions-dialog.component.ts - 94 + 102 @@ -8525,152 +8669,203 @@ Error retrieving metadata src/app/components/document-detail/document-detail.component.ts - 433 + 442 An error occurred loading content: src/app/components/document-detail/document-detail.component.ts - 535,537 + 545,547 src/app/components/document-detail/document-detail.component.ts - 992,994 + 1024,1026 Document was updated src/app/components/document-detail/document-detail.component.ts - 661 + 685 Document was updated at . src/app/components/document-detail/document-detail.component.ts - 662 + 686 Reload to discard your local unsaved edits and load the latest remote version. src/app/components/document-detail/document-detail.component.ts - 663 + 687 Reload src/app/components/document-detail/document-detail.component.ts - 665 + 689 Document reloaded with latest changes. src/app/components/document-detail/document-detail.component.ts - 721 + 745 Document reloaded. src/app/components/document-detail/document-detail.component.ts - 732 + 756 Next document src/app/components/document-detail/document-detail.component.ts - 834 + 858 Previous document src/app/components/document-detail/document-detail.component.ts - 844 + 868 Close document src/app/components/document-detail/document-detail.component.ts - 852 + 876 src/app/services/open-documents.service.ts - 143 + 151 Save document src/app/components/document-detail/document-detail.component.ts - 859 + 883 Save and close / next src/app/components/document-detail/document-detail.component.ts - 868 + 892 Error retrieving version content src/app/components/document-detail/document-detail.component.ts - 975 + 1006 + + + + Unsaved Changes + + src/app/components/document-detail/document-detail.component.ts + 1050 + + + src/app/guards/dirty-form.guard.ts + 15 + + + src/app/guards/dirty-saved-view.guard.ts + 27 + + + src/app/services/open-documents.service.ts + 143 + + + src/app/services/open-documents.service.ts + 170 + + + + You have unsaved changes to the content of this version. + + src/app/components/document-detail/document-detail.component.ts + 1051 + + + + Switching versions will discard them. + + src/app/components/document-detail/document-detail.component.ts + 1052 + + + + Discard and switch + + src/app/components/document-detail/document-detail.component.ts + 1054 + + + + Save and switch + + src/app/components/document-detail/document-detail.component.ts + 1056 Error retrieving suggestions. src/app/components/document-detail/document-detail.component.ts - 1035 + 1099 Document "" saved successfully. src/app/components/document-detail/document-detail.component.ts - 1247 + 1311 src/app/components/document-detail/document-detail.component.ts - 1274 + 1339 Error saving document "" src/app/components/document-detail/document-detail.component.ts - 1280 + 1345 Error saving document src/app/components/document-detail/document-detail.component.ts - 1335 + 1400 Do you really want to move the document "" to the trash? src/app/components/document-detail/document-detail.component.ts - 1368 + 1433 Documents can be restored prior to permanent deletion. src/app/components/document-detail/document-detail.component.ts - 1369 + 1434 src/app/components/document-list/bulk-editor/bulk-editor.component.ts @@ -8681,14 +8876,14 @@ Error deleting document src/app/components/document-detail/document-detail.component.ts - 1390 + 1455 Reprocess confirm src/app/components/document-detail/document-detail.component.ts - 1410 + 1475 src/app/components/document-list/bulk-editor/bulk-editor.component.ts @@ -8699,102 +8894,102 @@ This operation will permanently recreate the archive file for this document. src/app/components/document-detail/document-detail.component.ts - 1411 + 1476 The archive file will be re-generated with the current settings. src/app/components/document-detail/document-detail.component.ts - 1412 + 1477 Reprocess operation for "" will begin in the background. src/app/components/document-detail/document-detail.component.ts - 1425 + 1490 Error executing operation src/app/components/document-detail/document-detail.component.ts - 1436 + 1501 Error downloading document src/app/components/document-detail/document-detail.component.ts - 1500 + 1565 Page Fit src/app/components/document-detail/document-detail.component.ts - 1578 + 1643 PDF edit operation for "" will begin in the background. src/app/components/document-detail/document-detail.component.ts - 1821 + 1886 Error executing PDF edit operation src/app/components/document-detail/document-detail.component.ts - 1833 + 1898 Please enter the current password before attempting to remove it. src/app/components/document-detail/document-detail.component.ts - 1844 + 1909 Password removal operation for "" will begin in the background. src/app/components/document-detail/document-detail.component.ts - 1878 + 1943 Error executing password removal operation src/app/components/document-detail/document-detail.component.ts - 1892 + 1957 Print failed. src/app/components/document-detail/document-detail.component.ts - 1942 + 2007 Error loading document for printing. src/app/components/document-detail/document-detail.component.ts - 1951 + 2016 An error occurred loading tiff: src/app/components/document-detail/document-detail.component.ts - 2034 + 2099 src/app/components/document-detail/document-detail.component.ts - 2040 + 2105 @@ -9746,7 +9941,7 @@ src/app/components/document-list/filter-editor/filter-editor.component.ts - 202 + 206 src/app/data/document.ts @@ -9949,63 +10144,84 @@ Title & content src/app/components/document-list/filter-editor/filter-editor.component.ts - 200 + 204 File type src/app/components/document-list/filter-editor/filter-editor.component.ts - 203 + 207 + + + + Duplicates + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 212 Custom fields (Deprecated) src/app/components/document-list/filter-editor/filter-editor.component.ts - 213 + 218 More like src/app/components/document-list/filter-editor/filter-editor.component.ts - 218 + 223 equals src/app/components/document-list/filter-editor/filter-editor.component.ts - 224 + 229 is empty src/app/components/document-list/filter-editor/filter-editor.component.ts - 228 + 233 is not empty src/app/components/document-list/filter-editor/filter-editor.component.ts - 232 + 237 greater than src/app/components/document-list/filter-editor/filter-editor.component.ts - 236 + 241 less than src/app/components/document-list/filter-editor/filter-editor.component.ts - 240 + 245 + + + + exist + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 252 + + + + do not exist + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 256 @@ -10014,14 +10230,14 @@ )?.name"/> src/app/components/document-list/filter-editor/filter-editor.component.ts - 281,285 + 297,301 Without correspondent src/app/components/document-list/filter-editor/filter-editor.component.ts - 287 + 303 @@ -10030,14 +10246,14 @@ )?.name"/> src/app/components/document-list/filter-editor/filter-editor.component.ts - 293,297 + 309,313 Without document type src/app/components/document-list/filter-editor/filter-editor.component.ts - 299 + 315 @@ -10046,77 +10262,91 @@ )?.name"/> src/app/components/document-list/filter-editor/filter-editor.component.ts - 305,309 + 321,325 Without storage path src/app/components/document-list/filter-editor/filter-editor.component.ts - 311 + 327 Tag: src/app/components/document-list/filter-editor/filter-editor.component.ts - 315,317 + 331,333 Without any tag src/app/components/document-list/filter-editor/filter-editor.component.ts - 321 + 337 + + + + Without duplicates + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 343 + + + + With duplicates + + src/app/components/document-list/filter-editor/filter-editor.component.ts + 344 Custom fields query src/app/components/document-list/filter-editor/filter-editor.component.ts - 325 + 347 Title: src/app/components/document-list/filter-editor/filter-editor.component.ts - 329 + 351 Title & content: src/app/components/document-list/filter-editor/filter-editor.component.ts - 333 + 355 ASN: src/app/components/document-list/filter-editor/filter-editor.component.ts - 336 + 358 Owner: src/app/components/document-list/filter-editor/filter-editor.component.ts - 339 + 361 Owner not in: src/app/components/document-list/filter-editor/filter-editor.component.ts - 342 + 364 Without an owner src/app/components/document-list/filter-editor/filter-editor.component.ts - 345 + 367 @@ -10737,13 +10967,6 @@ 183,184 - - Error retrieving mail accounts - - src/app/components/manage/mail/mail.component.ts - 110 - - Error retrieving mail rules @@ -12125,25 +12348,6 @@ 16 - - Unsaved Changes - - src/app/guards/dirty-form.guard.ts - 15 - - - src/app/guards/dirty-saved-view.guard.ts - 27 - - - src/app/services/open-documents.service.ts - 135 - - - src/app/services/open-documents.service.ts - 162 - - You have unsaved changes. @@ -12152,7 +12356,7 @@ src/app/services/open-documents.service.ts - 163 + 171 @@ -12292,315 +12496,315 @@ You have unsaved changes to the document src/app/services/open-documents.service.ts - 137 + 145 Are you sure you want to close this document? src/app/services/open-documents.service.ts - 141 + 149 Are you sure you want to close all documents? src/app/services/open-documents.service.ts - 164 + 172 Close documents src/app/services/open-documents.service.ts - 166 + 174 English (US) src/app/services/settings.service.ts - 55 + 56 Afrikaans src/app/services/settings.service.ts - 61 + 62 Arabic src/app/services/settings.service.ts - 67 + 68 Belarusian src/app/services/settings.service.ts - 73 + 74 Bulgarian src/app/services/settings.service.ts - 79 + 80 Catalan src/app/services/settings.service.ts - 85 + 86 Czech src/app/services/settings.service.ts - 91 + 92 Danish src/app/services/settings.service.ts - 97 + 98 German src/app/services/settings.service.ts - 103 + 104 Greek src/app/services/settings.service.ts - 109 + 110 English (GB) src/app/services/settings.service.ts - 115 + 116 Spanish src/app/services/settings.service.ts - 121 + 122 Finnish src/app/services/settings.service.ts - 127 + 128 French src/app/services/settings.service.ts - 133 + 134 Hungarian src/app/services/settings.service.ts - 139 + 140 Indonesian src/app/services/settings.service.ts - 145 + 146 Italian src/app/services/settings.service.ts - 151 + 152 Japanese src/app/services/settings.service.ts - 157 + 158 Korean src/app/services/settings.service.ts - 163 + 164 Luxembourgish src/app/services/settings.service.ts - 169 + 170 Dutch src/app/services/settings.service.ts - 175 + 176 Norwegian src/app/services/settings.service.ts - 181 + 182 Persian src/app/services/settings.service.ts - 187 + 188 Polish src/app/services/settings.service.ts - 193 + 194 Portuguese (Brazil) src/app/services/settings.service.ts - 199 + 200 Portuguese src/app/services/settings.service.ts - 205 + 206 Romanian src/app/services/settings.service.ts - 211 + 212 Russian src/app/services/settings.service.ts - 217 + 218 Slovak src/app/services/settings.service.ts - 223 + 224 Slovenian src/app/services/settings.service.ts - 229 + 230 Serbian src/app/services/settings.service.ts - 235 + 236 Swedish src/app/services/settings.service.ts - 241 + 242 Turkish src/app/services/settings.service.ts - 247 + 248 Ukrainian src/app/services/settings.service.ts - 253 + 254 Vietnamese src/app/services/settings.service.ts - 259 + 260 Chinese Simplified src/app/services/settings.service.ts - 265 + 266 Chinese Traditional src/app/services/settings.service.ts - 271 + 272 ISO 8601 src/app/services/settings.service.ts - 279 + 280 Successfully completed one-time migratration of settings to the database! src/app/services/settings.service.ts - 648 + 661 Unable to migrate settings to the database, please try saving manually. src/app/services/settings.service.ts - 649 + 662 You can restart the tour from the settings page. src/app/services/settings.service.ts - 732 + 745 diff --git a/src-ui/src/app/components/admin/config/config.component.html b/src-ui/src/app/components/admin/config/config.component.html index e516ba941..31e9aecfa 100644 --- a/src-ui/src/app/components/admin/config/config.component.html +++ b/src-ui/src/app/components/admin/config/config.component.html @@ -23,17 +23,30 @@
-
+
{{option.title}}
+ @if (isExternallyConfigured(option.config_key)) { + @if (isSet(option.key)) { + Overrides external + } @else { + Set externally + } + } @if (isSet(option.key)) { - + @if (isExternallyConfigured(option.config_key)) { + + } @else { + + } }
diff --git a/src-ui/src/app/components/admin/config/config.component.spec.ts b/src-ui/src/app/components/admin/config/config.component.spec.ts index a99171f93..650761c7d 100644 --- a/src-ui/src/app/components/admin/config/config.component.spec.ts +++ b/src-ui/src/app/components/admin/config/config.component.spec.ts @@ -163,6 +163,19 @@ describe('ConfigComponent', () => { expect(component.configForm.get('barcodes_enabled').value).toBeNull() }) + it('should identify externally configured options', () => { + component.externallyConfiguredVariables = new Set([ + 'PAPERLESS_OCR_LANGUAGE', + ]) + + expect( + component.isExternallyConfigured('PAPERLESS_OCR_LANGUAGE') + ).toBeTruthy() + expect( + component.isExternallyConfigured('PAPERLESS_OCR_OUTPUT_TYPE') + ).toBeFalsy() + }) + it('should group options into sections within a category, or not', () => { const sections = component.getCategorySections(ConfigCategory.OCR) expect(sections).toEqual([null, ConfigSection.RemoteOCR]) diff --git a/src-ui/src/app/components/admin/config/config.component.ts b/src-ui/src/app/components/admin/config/config.component.ts index 0e3f432e2..570eb7d55 100644 --- a/src-ui/src/app/components/admin/config/config.component.ts +++ b/src-ui/src/app/components/admin/config/config.component.ts @@ -69,6 +69,7 @@ export class ConfigComponent public configForm = new FormGroup({}) public errors = {} + public externallyConfiguredVariables = new Set() get optionCategories(): string[] { return Object.values(ConfigCategory) @@ -152,6 +153,9 @@ export class ConfigComponent } private initialize(config: PaperlessConfig) { + this.externallyConfiguredVariables = new Set( + config.externally_configured_variables ?? [] + ) if (!this.store) { this.store = new BehaviorSubject(config) @@ -162,7 +166,9 @@ export class ConfigComponent this.configForm.patchValue(state, { emitEvent: false }) }) - this.isDirty$ = dirtyCheck(this.configForm, this.store.asObservable()) + this.isDirty$ = dirtyCheck(this.configForm, this.store.asObservable(), { + excludeKeys: ['externally_configured_variables'], + }) } this.configForm.patchValue(config) @@ -227,6 +233,10 @@ export class ConfigComponent return this.configForm.get(key).value != null } + public isExternallyConfigured(configKey: string): boolean { + return this.externallyConfiguredVariables.has(configKey) + } + public resetOption(key: string) { this.configForm.get(key).setValue(null) } diff --git a/src-ui/src/app/components/admin/settings/settings.component.html b/src-ui/src/app/components/admin/settings/settings.component.html index 569815d35..b520e8218 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.html +++ b/src-ui/src/app/components/admin/settings/settings.component.html @@ -112,6 +112,22 @@ +

Sidebar items to show:

+ @for (option of sidebarItemOptions; track option.id) { +
+ + +
+ } +
@@ -237,6 +253,12 @@
+
+
+ +
+
+
diff --git a/src-ui/src/app/components/admin/settings/settings.component.spec.ts b/src-ui/src/app/components/admin/settings/settings.component.spec.ts index 7d24063b4..71889e74b 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.spec.ts +++ b/src-ui/src/app/components/admin/settings/settings.component.spec.ts @@ -24,7 +24,7 @@ import { SystemStatus, SystemStatusItemStatus, } from 'src/app/data/system-status' -import { SETTINGS_KEYS } from 'src/app/data/ui-settings' +import { HideableSidebarItemID, SETTINGS_KEYS } from 'src/app/data/ui-settings' import { IfOwnerDirective } from 'src/app/directives/if-owner.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { PermissionsGuard } from 'src/app/guards/permissions.guard' @@ -209,6 +209,45 @@ describe('SettingsComponent', () => { fixture.detectChanges() } + it('supports configuring sidebar items and canceling changes', () => { + completeSetup() + + component.toggleSidebarItem(HideableSidebarItemID.Workflows, false) + fixture.detectChanges() + + expect(component.settingsForm.value.sidebarHiddenItems).toContain( + HideableSidebarItemID.Workflows + ) + + settingsService.updateSidebarItemVisibility( + HideableSidebarItemID.Mail, + false + ) + + expect(component.settingsForm.value.sidebarHiddenItems).toContain( + HideableSidebarItemID.Mail + ) + + component.reset() + + expect(component.settingsForm.value.sidebarHiddenItems).not.toContain( + HideableSidebarItemID.Workflows + ) + expect(component.settingsForm.value.sidebarHiddenItems).not.toContain( + HideableSidebarItemID.Mail + ) + }) + + it('enables sidebar item controls on general settings until destroyed', () => { + completeSetup() + + expect(settingsService.organizingSidebarItems()).toBe(true) + + component.ngOnDestroy() + + expect(settingsService.organizingSidebarItems()).toBe(false) + }) + it('should support tabbed settings & change URL, prevent navigation if dirty confirmation rejected', async () => { completeSetup() const navigateSpy = jest.spyOn(router, 'navigate') @@ -249,6 +288,7 @@ describe('SettingsComponent', () => { it('should support save local settings updating appearance settings and calling API, show error', () => { completeSetup() + component.toggleSidebarItem(HideableSidebarItemID.Workflows, false) const toastErrorSpy = jest.spyOn(toastService, 'showError') const toastSpy = jest.spyOn(toastService, 'show') const storeSpy = jest.spyOn(settingsService, 'storeSettings') @@ -267,7 +307,10 @@ describe('SettingsComponent', () => { expect(toastErrorSpy).toHaveBeenCalled() expect(storeSpy).toHaveBeenCalled() expect(appearanceSettingsSpy).not.toHaveBeenCalled() - expect(setSpy).toHaveBeenCalledTimes(32) + expect(setSpy).toHaveBeenCalledTimes(34) + expect(setSpy).toHaveBeenCalledWith(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, [ + HideableSidebarItemID.Workflows, + ]) // succeed storeSpy.mockReturnValueOnce(of(true)) diff --git a/src-ui/src/app/components/admin/settings/settings.component.ts b/src-ui/src/app/components/admin/settings/settings.component.ts index b9409fe06..9076d2a3e 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.ts +++ b/src-ui/src/app/components/admin/settings/settings.component.ts @@ -39,7 +39,12 @@ import { SystemStatus, SystemStatusItemStatus, } from 'src/app/data/system-status' -import { GlobalSearchType, SETTINGS_KEYS } from 'src/app/data/ui-settings' +import { + GlobalSearchType, + HIDEABLE_SIDEBAR_ITEM_IDS, + HideableSidebarItemID, + SETTINGS_KEYS, +} from 'src/app/data/ui-settings' import { User } from 'src/app/data/user' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' @@ -102,6 +107,14 @@ const documentDetailFieldOptions = [ { id: DocumentDetailFieldID.Tags, label: $localize`Tags` }, ] +const sidebarItemLabels: Record = { + [HideableSidebarItemID.Dashboard]: $localize`Dashboard`, + [HideableSidebarItemID.SavedViews]: $localize`Saved Views`, + [HideableSidebarItemID.Workflows]: $localize`Workflows`, + [HideableSidebarItemID.Mail]: $localize`Mail`, + [HideableSidebarItemID.Documentation]: $localize`Documentation`, +} + @Component({ selector: 'pngx-settings', templateUrl: './settings.component.html', @@ -149,6 +162,7 @@ export class SettingsComponent bulkEditApplyOnClose: new FormControl(null), documentListItemPerPage: new FormControl(null), slimSidebarEnabled: new FormControl(null), + sidebarHiddenItems: new FormControl([]), darkModeUseSystem: new FormControl(null), darkModeEnabled: new FormControl(null), darkModeInvertThumbs: new FormControl(null), @@ -168,6 +182,7 @@ export class SettingsComponent pdfEditorDefaultEditMode: new FormControl(null), documentEditingRemoveInboxTags: new FormControl(null), documentEditingOverlayThumbnail: new FormControl(null), + documentEditingAutoSuggest: new FormControl(null), documentDetailsHiddenFields: new FormControl([]), searchDbOnly: new FormControl(null), searchLink: new FormControl(null), @@ -185,6 +200,7 @@ export class SettingsComponent store: BehaviorSubject storeSub: Subscription + sidebarItemsSub: Subscription isDirty$: Observable isDirty: boolean = false unsubscribeNotifier: Subject = new Subject() @@ -202,6 +218,10 @@ export class SettingsComponent public readonly PdfEditorEditMode = PdfEditorEditMode public readonly documentDetailFieldOptions = documentDetailFieldOptions + public readonly sidebarItemOptions = HIDEABLE_SIDEBAR_ITEM_IDS.map((id) => ({ + id, + label: sidebarItemLabels[id], + })) get systemStatusHasErrors(): boolean { const status = this.systemStatus() @@ -229,6 +249,10 @@ export class SettingsComponent constructor() { super() + this.sidebarItemsSub = + this.settings.sidebarHiddenItemsEditingChanged.subscribe((hiddenItems) => + this.settingsForm.controls.sidebarHiddenItems.setValue(hiddenItems) + ) this.settings.settingsSaved.subscribe(() => { if (!this.savePending) this.initialize() this.savedViewsService.maybeRefreshDocumentCounts() @@ -278,14 +302,21 @@ export class SettingsComponent this.activatedRoute.paramMap.subscribe((paramMap) => { const section = paramMap.get('section') + let navID = SettingsNavIDs.General if (section) { const navIDKey: string = Object.keys(SettingsNavIDs).find( (navID) => navID.toLowerCase() == section ) if (navIDKey) { - this.activeNavID.set(SettingsNavIDs[navIDKey]) + navID = SettingsNavIDs[navIDKey] } } + this.activeNavID.set(navID) + this.settings.sidebarHiddenItemsEditing.set( + navID === SettingsNavIDs.General + ? [...this.settingsForm.controls.sidebarHiddenItems.value] + : null + ) }) } @@ -309,6 +340,7 @@ export class SettingsComponent SETTINGS_KEYS.DOCUMENT_LIST_SIZE ), slimSidebarEnabled: this.settings.get(SETTINGS_KEYS.SLIM_SIDEBAR), + sidebarHiddenItems: this.settings.get(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS), darkModeUseSystem: this.settings.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM), darkModeEnabled: this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED), darkModeInvertThumbs: this.settings.get( @@ -368,6 +400,9 @@ export class SettingsComponent documentEditingOverlayThumbnail: this.settings.get( SETTINGS_KEYS.DOCUMENT_EDITING_OVERLAY_THUMBNAIL ), + documentEditingAutoSuggest: this.settings.get( + SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST + ), documentDetailsHiddenFields: this.settings.get( SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS ), @@ -432,6 +467,12 @@ export class SettingsComponent this.settingsForm.patchValue(currentFormValue) } + if (this.settings.organizingSidebarItems()) { + this.settings.sidebarHiddenItemsEditing.set([ + ...this.settingsForm.controls.sidebarHiddenItems.value, + ]) + } + if (this.canViewSystemStatus) { this.systemStatusService.get().subscribe((status) => { this.systemStatus.set(status) @@ -440,8 +481,18 @@ export class SettingsComponent } ngOnDestroy() { + this.settings.sidebarHiddenItemsEditing.set(null) if (this.isDirty) this.settings.updateAppearanceSettings() // in case user changed appearance but didn't save this.storeSub && this.storeSub.unsubscribe() + this.sidebarItemsSub.unsubscribe() + } + + isSidebarItemShown(item: HideableSidebarItemID): boolean { + return !(this.settingsForm.value.sidebarHiddenItems || []).includes(item) + } + + toggleSidebarItem(item: HideableSidebarItemID, checked: boolean): void { + this.settings.updateSidebarItemVisibility(item, checked) } public saveSettings() { @@ -469,6 +520,10 @@ export class SettingsComponent SETTINGS_KEYS.SLIM_SIDEBAR, this.settingsForm.value.slimSidebarEnabled ) + this.settings.set( + SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, + this.settingsForm.value.sidebarHiddenItems + ) this.settings.set( SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, this.settingsForm.value.darkModeUseSystem @@ -565,6 +620,10 @@ export class SettingsComponent SETTINGS_KEYS.DOCUMENT_EDITING_OVERLAY_THUMBNAIL, this.settingsForm.value.documentEditingOverlayThumbnail ) + this.settings.set( + SETTINGS_KEYS.DOCUMENT_EDITING_AUTO_SUGGEST, + this.settingsForm.value.documentEditingAutoSuggest + ) this.settings.set( SETTINGS_KEYS.DOCUMENT_DETAILS_HIDDEN_FIELDS, this.settingsForm.value.documentDetailsHiddenFields @@ -624,6 +683,11 @@ export class SettingsComponent reset() { this.settingsForm.patchValue(this.store.getValue()) + if (this.settings.organizingSidebarItems()) { + this.settings.sidebarHiddenItemsEditing.set([ + ...this.settingsForm.controls.sidebarHiddenItems.value, + ]) + } } clearThemeColor() { diff --git a/src-ui/src/app/components/admin/tasks/tasks.component.ts b/src-ui/src/app/components/admin/tasks/tasks.component.ts index f634a87f7..4116f62d4 100644 --- a/src-ui/src/app/components/admin/tasks/tasks.component.ts +++ b/src-ui/src/app/components/admin/tasks/tasks.component.ts @@ -99,6 +99,10 @@ const TASK_TYPE_OPTIONS: Array<{ value: PaperlessTaskType.BulkDelete, label: $localize`Bulk Delete`, }, + { + value: PaperlessTaskType.ApplyAiSuggestions, + label: $localize`Apply AI Suggestions`, + }, ] const TRIGGER_SOURCE_OPTIONS: Array<{ diff --git a/src-ui/src/app/components/app-frame/app-frame.component.html b/src-ui/src/app/components/app-frame/app-frame.component.html index a0c10c94e..bafc34cd3 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.html +++ b/src-ui/src/app/components/app-frame/app-frame.component.html @@ -86,12 +86,15 @@ }