Compare commits

..

1 Commits

Author SHA1 Message Date
Trenton H
367f47b2fd Enables testing against 3.13 for fun 2025-10-01 08:50:33 -07:00
30 changed files with 1892 additions and 2127 deletions

View File

@@ -25,7 +25,7 @@ jobs:
steps: steps:
- name: Check if workflow should run - name: Check if workflow should run
id: check id: check
uses: actions/github-script@v8 uses: actions/github-script@v7
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
script: | script: |
@@ -69,7 +69,7 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v5
- name: Install python - name: Install python
uses: actions/setup-python@v6 uses: actions/setup-python@v5
with: with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }} python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Check files - name: Check files
@@ -84,7 +84,7 @@ jobs:
uses: actions/checkout@v5 uses: actions/checkout@v5
- name: Set up Python - name: Set up Python
id: setup-python id: setup-python
uses: actions/setup-python@v6 uses: actions/setup-python@v5
with: with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }} python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Install uv - name: Install uv
@@ -127,7 +127,7 @@ jobs:
- pre-commit - pre-commit
strategy: strategy:
matrix: matrix:
python-version: ['3.10', '3.11', '3.12'] python-version: ['3.10', '3.11', '3.12', '3.13']
fail-fast: false fail-fast: false
steps: steps:
- name: Checkout - name: Checkout
@@ -138,7 +138,7 @@ jobs:
docker compose --file ${{ github.workspace }}/docker/compose/docker-compose.ci-test.yml up --detach docker compose --file ${{ github.workspace }}/docker/compose/docker-compose.ci-test.yml up --detach
- name: Set up Python - name: Set up Python
id: setup-python id: setup-python
uses: actions/setup-python@v6 uses: actions/setup-python@v5
with: with:
python-version: "${{ matrix.python-version }}" python-version: "${{ matrix.python-version }}"
- name: Install uv - name: Install uv
@@ -207,7 +207,7 @@ jobs:
with: with:
version: 10 version: 10
- name: Use Node.js 20 - name: Use Node.js 20
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
cache: 'pnpm' cache: 'pnpm'
@@ -240,7 +240,7 @@ jobs:
with: with:
version: 10 version: 10
- name: Use Node.js 20 - name: Use Node.js 20
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
cache: 'pnpm' cache: 'pnpm'
@@ -288,7 +288,7 @@ jobs:
with: with:
version: 10 version: 10
- name: Use Node.js 20 - name: Use Node.js 20
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
cache: 'pnpm' cache: 'pnpm'
@@ -331,7 +331,7 @@ jobs:
with: with:
version: 10 version: 10
- name: Use Node.js 20 - name: Use Node.js 20
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
cache: 'pnpm' cache: 'pnpm'
@@ -473,7 +473,7 @@ jobs:
uses: actions/checkout@v5 uses: actions/checkout@v5
- name: Set up Python - name: Set up Python
id: setup-python id: setup-python
uses: actions/setup-python@v6 uses: actions/setup-python@v5
with: with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }} python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Install uv - name: Install uv
@@ -621,7 +621,7 @@ jobs:
ref: main ref: main
- name: Set up Python - name: Set up Python
id: setup-python id: setup-python
uses: actions/setup-python@v6 uses: actions/setup-python@v5
with: with:
python-version: ${{ env.DEFAULT_PYTHON_VERSION }} python-version: ${{ env.DEFAULT_PYTHON_VERSION }}
- name: Install uv - name: Install uv
@@ -653,7 +653,7 @@ jobs:
git commit -am "Changelog ${{ needs.publish-release.outputs.version }} - GHA" git commit -am "Changelog ${{ needs.publish-release.outputs.version }} - GHA"
git push origin ${{ needs.publish-release.outputs.version }}-changelog git push origin ${{ needs.publish-release.outputs.version }}-changelog
- name: Create Pull Request - name: Create Pull Request
uses: actions/github-script@v8 uses: actions/github-script@v7
with: with:
script: | script: |
const { repo, owner } = context.repo; const { repo, owner } = context.repo;

View File

@@ -6,9 +6,10 @@
# This workflow will not trigger runs on forked repos. # This workflow will not trigger runs on forked repos.
name: Cleanup Image Tags name: Cleanup Image Tags
on: on:
workflow_dispatch: delete:
schedule: push:
- cron: '0 0 * * 0' paths:
- ".github/workflows/cleanup-tags.yml"
concurrency: concurrency:
group: registry-tags-cleanup group: registry-tags-cleanup
cancel-in-progress: false cancel-in-progress: false

View File

@@ -12,7 +12,7 @@ jobs:
steps: steps:
- name: Label PR by file path or branch name - name: Label PR by file path or branch name
# see .github/labeler.yml for the labeler config # see .github/labeler.yml for the labeler config
uses: actions/labeler@v6 uses: actions/labeler@v5
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Label by size - name: Label by size
@@ -26,7 +26,7 @@ jobs:
fail_if_xl: 'false' fail_if_xl: 'false'
excluded_files: /\.lock$/ /\.txt$/ ^src-ui/pnpm-lock\.yaml$ ^src-ui/messages\.xlf$ ^src/locale/en_US/LC_MESSAGES/django\.po$ excluded_files: /\.lock$/ /\.txt$/ ^src-ui/pnpm-lock\.yaml$ ^src-ui/messages\.xlf$ ^src/locale/en_US/LC_MESSAGES/django\.po$
- name: Label by PR title - name: Label by PR title
uses: actions/github-script@v8 uses: actions/github-script@v7
with: with:
script: | script: |
const pr = context.payload.pull_request; const pr = context.payload.pull_request;
@@ -52,7 +52,7 @@ jobs:
} }
- name: Label bot-generated PRs - name: Label bot-generated PRs
if: ${{ contains(github.actor, 'dependabot') || contains(github.actor, 'crowdin-bot') }} if: ${{ contains(github.actor, 'dependabot') || contains(github.actor, 'crowdin-bot') }}
uses: actions/github-script@v8 uses: actions/github-script@v7
with: with:
script: | script: |
const pr = context.payload.pull_request; const pr = context.payload.pull_request;
@@ -77,7 +77,7 @@ jobs:
} }
- name: Welcome comment - name: Welcome comment
if: ${{ !contains(github.actor, 'bot') }} if: ${{ !contains(github.actor, 'bot') }}
uses: actions/github-script@v8 uses: actions/github-script@v7
with: with:
script: | script: |
const pr = context.payload.pull_request; const pr = context.payload.pull_request;

View File

@@ -15,7 +15,7 @@ jobs:
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/stale@v10 - uses: actions/stale@v9
with: with:
days-before-stale: 7 days-before-stale: 7
days-before-close: 14 days-before-close: 14
@@ -57,7 +57,7 @@ jobs:
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@v7
with: with:
script: | script: |
function sleep(ms) { function sleep(ms) {
@@ -114,7 +114,7 @@ jobs:
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@v7
with: with:
script: | script: |
function sleep(ms) { function sleep(ms) {
@@ -206,7 +206,7 @@ jobs:
if: github.repository_owner == 'paperless-ngx' if: github.repository_owner == 'paperless-ngx'
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/github-script@v8 - uses: actions/github-script@v7
with: with:
script: | script: |
function sleep(ms) { function sleep(ms) {

View File

@@ -17,7 +17,7 @@ jobs:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
- name: Set up Python - name: Set up Python
id: setup-python id: setup-python
uses: actions/setup-python@v6 uses: actions/setup-python@v5
- name: Install system dependencies - name: Install system dependencies
run: | run: |
sudo apt-get update -qq sudo apt-get update -qq
@@ -38,7 +38,7 @@ jobs:
with: with:
version: 10 version: 10
- name: Use Node.js 20 - name: Use Node.js 20
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
cache: 'pnpm' cache: 'pnpm'

View File

@@ -170,11 +170,11 @@ Available options are `postgresql` and `mariadb`.
!!! note !!! note
A small pool is typically sufficient — for example, a size of 4. A small pool is typically sufficient — for example, a size of 4.
Make sure your PostgreSQL server's max_connections setting is large enough to handle: Make sure your PostgreSQL server's max_connections setting is large enough to handle:
```(Paperless workers + Celery workers) × pool size + safety margin``` ```(Paperless workers + Celery workers) × pool size + safety margin```
For example, with 4 Paperless workers and 2 Celery workers, and a pool size of 4: For example, with 4 Paperless workers and 2 Celery workers, and a pool size of 4:
(4 + 2) × 4 + 10 = 34 connections required. (4 + 2) × 4 + 10 = 34 connections required.
#### [`PAPERLESS_DB_READ_CACHE_ENABLED=<bool>`](#PAPERLESS_DB_READ_CACHE_ENABLED) {#PAPERLESS_DB_READ_CACHE_ENABLED} #### [`PAPERLESS_DB_READ_CACHE_ENABLED=<bool>`](#PAPERLESS_DB_READ_CACHE_ENABLED) {#PAPERLESS_DB_READ_CACHE_ENABLED}
@@ -184,9 +184,9 @@ Available options are `postgresql` and `mariadb`.
!!! danger !!! danger
**Do not modify the database outside the application while it is running.** **Do not modify the database outside the application while it is running.**
This includes actions such as restoring a backup, upgrading the database, or performing manual inserts. All external modifications must be done **only when the application is stopped**. This includes actions such as restoring a backup, upgrading the database, or performing manual inserts. All external modifications must be done **only when the application is stopped**.
After making any such changes, you **must invalidate the DB read cache** using the `invalidate_cachalot` management command. After making any such changes, you **must invalidate the DB read cache** using the `invalidate_cachalot` management command.
#### [`PAPERLESS_READ_CACHE_TTL=<int>`](#PAPERLESS_READ_CACHE_TTL) {#PAPERLESS_READ_CACHE_TTL} #### [`PAPERLESS_READ_CACHE_TTL=<int>`](#PAPERLESS_READ_CACHE_TTL) {#PAPERLESS_READ_CACHE_TTL}
@@ -196,7 +196,7 @@ Available options are `postgresql` and `mariadb`.
!!! warning !!! warning
A high TTL increases memory usage over time. Memory may be used until end of TTL, even if the cache is invalidated with the `invalidate_cachalot` command. A high TTL increases memory usage over time. Memory may be used until end of TTL, even if the cache is invalidated with the `invalidate_cachalot` command.
In case of an out-of-memory (OOM) situation, Redis may stop accepting new data — including cache entries, scheduled tasks, and documents to consume. In case of an out-of-memory (OOM) situation, Redis may stop accepting new data — including cache entries, scheduled tasks, and documents to consume.
If your system has limited RAM, consider configuring a dedicated Redis instance for the read cache, with a memory limit and the eviction policy set to `allkeys-lru`. If your system has limited RAM, consider configuring a dedicated Redis instance for the read cache, with a memory limit and the eviction policy set to `allkeys-lru`.

View File

@@ -414,7 +414,7 @@ fields and permissions, which will be merged.
#### Types {#workflow-trigger-types} #### Types {#workflow-trigger-types}
Currently, there are four events that correspond to workflow trigger 'types': Currently, there are three events that correspond to workflow trigger 'types':
1. **Consumption Started**: _before_ a document is consumed, so events can include filters by source (mail, consumption 1. **Consumption Started**: _before_ a document is consumed, so events can include filters by source (mail, consumption
folder or API), file path, file name, mail rule folder or API), file path, file name, mail rule
@@ -427,7 +427,7 @@ Currently, there are four events that correspond to workflow trigger 'types':
added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date (positive added, created, updated date or you can specify a (date) custom field. You can also specify a day offset from the date (positive
offsets will trigger after the date, negative offsets will trigger before). offsets will trigger after the date, negative offsets will trigger before).
The following flow diagram illustrates the four document trigger types: The following flow diagram illustrates the three document trigger types:
```mermaid ```mermaid
flowchart TD flowchart TD

View File

@@ -5,14 +5,14 @@
<trans-unit id="ngb.alert.close" datatype="html"> <trans-unit id="ngb.alert.close" datatype="html">
<source>Close</source> <source>Close</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/alert/alert.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/alert/alert.ts</context>
<context context-type="linenumber">50</context> <context context-type="linenumber">50</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.carousel.slide-number" datatype="html"> <trans-unit id="ngb.carousel.slide-number" datatype="html">
<source> Slide <x id="INTERPOLATION" equiv-text="ueryList&lt;NgbSli"/> of <x id="INTERPOLATION_1" equiv-text="EventSource = N"/> </source> <source> Slide <x id="INTERPOLATION" equiv-text="ueryList&lt;NgbSli"/> of <x id="INTERPOLATION_1" equiv-text="EventSource = N"/> </source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/carousel/carousel.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/carousel/carousel.ts</context>
<context context-type="linenumber">131,135</context> <context context-type="linenumber">131,135</context>
</context-group> </context-group>
<note priority="1" from="description">Currently selected slide number read by screen reader</note> <note priority="1" from="description">Currently selected slide number read by screen reader</note>
@@ -20,212 +20,212 @@
<trans-unit id="ngb.carousel.previous" datatype="html"> <trans-unit id="ngb.carousel.previous" datatype="html">
<source>Previous</source> <source>Previous</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/carousel/carousel.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/carousel/carousel.ts</context>
<context context-type="linenumber">157,159</context> <context context-type="linenumber">157,159</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.carousel.next" datatype="html"> <trans-unit id="ngb.carousel.next" datatype="html">
<source>Next</source> <source>Next</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/carousel/carousel.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/carousel/carousel.ts</context>
<context context-type="linenumber">198</context> <context context-type="linenumber">198</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.datepicker.previous-month" datatype="html"> <trans-unit id="ngb.datepicker.previous-month" datatype="html">
<source>Previous month</source> <source>Previous month</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/datepicker/datepicker-navigation.ts</context>
<context context-type="linenumber">83,85</context> <context context-type="linenumber">83,85</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/datepicker/datepicker-navigation.ts</context>
<context context-type="linenumber">112</context> <context context-type="linenumber">112</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.datepicker.next-month" datatype="html"> <trans-unit id="ngb.datepicker.next-month" datatype="html">
<source>Next month</source> <source>Next month</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/datepicker/datepicker-navigation.ts</context>
<context context-type="linenumber">112</context> <context context-type="linenumber">112</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/datepicker/datepicker-navigation.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/datepicker/datepicker-navigation.ts</context>
<context context-type="linenumber">112</context> <context context-type="linenumber">112</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.HH" datatype="html"> <trans-unit id="ngb.timepicker.HH" datatype="html">
<source>HH</source> <source>HH</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.toast.close-aria" datatype="html"> <trans-unit id="ngb.toast.close-aria" datatype="html">
<source>Close</source> <source>Close</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.datepicker.select-month" datatype="html"> <trans-unit id="ngb.datepicker.select-month" datatype="html">
<source>Select month</source> <source>Select month</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.first" datatype="html"> <trans-unit id="ngb.pagination.first" datatype="html">
<source>««</source> <source>««</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.hours" datatype="html"> <trans-unit id="ngb.timepicker.hours" datatype="html">
<source>Hours</source> <source>Hours</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.previous" datatype="html"> <trans-unit id="ngb.pagination.previous" datatype="html">
<source>«</source> <source>«</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.MM" datatype="html"> <trans-unit id="ngb.timepicker.MM" datatype="html">
<source>MM</source> <source>MM</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.next" datatype="html"> <trans-unit id="ngb.pagination.next" datatype="html">
<source>»</source> <source>»</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.datepicker.select-year" datatype="html"> <trans-unit id="ngb.datepicker.select-year" datatype="html">
<source>Select year</source> <source>Select year</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.minutes" datatype="html"> <trans-unit id="ngb.timepicker.minutes" datatype="html">
<source>Minutes</source> <source>Minutes</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.last" datatype="html"> <trans-unit id="ngb.pagination.last" datatype="html">
<source>»»</source> <source>»»</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.first-aria" datatype="html"> <trans-unit id="ngb.pagination.first-aria" datatype="html">
<source>First</source> <source>First</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.increment-hours" datatype="html"> <trans-unit id="ngb.timepicker.increment-hours" datatype="html">
<source>Increment hours</source> <source>Increment hours</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.previous-aria" datatype="html"> <trans-unit id="ngb.pagination.previous-aria" datatype="html">
<source>Previous</source> <source>Previous</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.decrement-hours" datatype="html"> <trans-unit id="ngb.timepicker.decrement-hours" datatype="html">
<source>Decrement hours</source> <source>Decrement hours</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.next-aria" datatype="html"> <trans-unit id="ngb.pagination.next-aria" datatype="html">
<source>Next</source> <source>Next</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.increment-minutes" datatype="html"> <trans-unit id="ngb.timepicker.increment-minutes" datatype="html">
<source>Increment minutes</source> <source>Increment minutes</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.pagination.last-aria" datatype="html"> <trans-unit id="ngb.pagination.last-aria" datatype="html">
<source>Last</source> <source>Last</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.decrement-minutes" datatype="html"> <trans-unit id="ngb.timepicker.decrement-minutes" datatype="html">
<source>Decrement minutes</source> <source>Decrement minutes</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.SS" datatype="html"> <trans-unit id="ngb.timepicker.SS" datatype="html">
<source>SS</source> <source>SS</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.seconds" datatype="html"> <trans-unit id="ngb.timepicker.seconds" datatype="html">
<source>Seconds</source> <source>Seconds</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.increment-seconds" datatype="html"> <trans-unit id="ngb.timepicker.increment-seconds" datatype="html">
<source>Increment seconds</source> <source>Increment seconds</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.decrement-seconds" datatype="html"> <trans-unit id="ngb.timepicker.decrement-seconds" datatype="html">
<source>Decrement seconds</source> <source>Decrement seconds</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="ngb.timepicker.PM" datatype="html"> <trans-unit id="ngb.timepicker.PM" datatype="html">
<source><x id="INTERPOLATION"/></source> <source><x id="INTERPOLATION"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/ngb-config.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/ngb-config.ts</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
@@ -233,7 +233,7 @@
<source><x id="INTERPOLATION" equiv-text="barConfig); <source><x id="INTERPOLATION" equiv-text="barConfig);
pu"/></source> pu"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.2_@angular+core@20.3.2_@angular+_4a8591e6ee586bf00b666f6438778cc7/node_modules/src/progressbar/progressbar.ts</context> <context context-type="sourcefile">node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.2.4_@angular+core@20.2.4_@angular+_db9461b4835bfc9061e01150e14e6256/node_modules/src/progressbar/progressbar.ts</context>
<context context-type="linenumber">41,42</context> <context context-type="linenumber">41,42</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
@@ -1636,7 +1636,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">45</context> <context context-type="linenumber">44</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context> <context context-type="sourcefile">src/app/components/admin/trash/trash.component.html</context>
@@ -1862,7 +1862,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">155</context> <context context-type="linenumber">153</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2134950584701094962" datatype="html"> <trans-unit id="2134950584701094962" datatype="html">
@@ -1918,77 +1918,63 @@
<source>Result</source> <source>Result</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">46</context> <context context-type="linenumber">45</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="5404910960991552159" datatype="html"> <trans-unit id="5404910960991552159" datatype="html">
<source>Dismiss selected</source> <source>Dismiss selected</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">110</context> <context context-type="linenumber">108</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8829078752502782653" datatype="html"> <trans-unit id="8829078752502782653" datatype="html">
<source>Dismiss all</source> <source>Dismiss all</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">111</context> <context context-type="linenumber">109</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="1323591410517879795" datatype="html"> <trans-unit id="1323591410517879795" datatype="html">
<source>Confirm Dismiss All</source> <source>Confirm Dismiss All</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">152</context> <context context-type="linenumber">150</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4157200209636243740" datatype="html"> <trans-unit id="4157200209636243740" datatype="html">
<source>Dismiss all <x id="PH" equiv-text="tasks.size"/> tasks?</source> <source>Dismiss all <x id="PH" equiv-text="tasks.size"/> tasks?</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">153</context> <context context-type="linenumber">151</context>
</context-group>
</trans-unit>
<trans-unit id="3597309129998924778" datatype="html">
<source>Error dismissing tasks</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">161</context>
</context-group>
</trans-unit>
<trans-unit id="2132179171926568807" datatype="html">
<source>Error dismissing task</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">170</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="9011556615675272238" datatype="html"> <trans-unit id="9011556615675272238" datatype="html">
<source>queued</source> <source>queued</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">246</context> <context context-type="linenumber">236</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6415892379431855826" datatype="html"> <trans-unit id="6415892379431855826" datatype="html">
<source>started</source> <source>started</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">248</context> <context context-type="linenumber">238</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="7510279840486540181" datatype="html"> <trans-unit id="7510279840486540181" datatype="html">
<source>completed</source> <source>completed</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">250</context> <context context-type="linenumber">240</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4083337005045748464" datatype="html"> <trans-unit id="4083337005045748464" datatype="html">
<source>failed</source> <source>failed</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context> <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.ts</context>
<context context-type="linenumber">252</context> <context context-type="linenumber">242</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3418677553313974490" datatype="html"> <trans-unit id="3418677553313974490" datatype="html">
@@ -2574,11 +2560,11 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1028</context> <context context-type="linenumber">1025</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1393</context> <context context-type="linenumber">1390</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -3190,7 +3176,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">981</context> <context context-type="linenumber">978</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -6668,7 +6654,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1392</context> <context context-type="linenumber">1389</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6490688569532630280" datatype="html"> <trans-unit id="6490688569532630280" datatype="html">
@@ -7032,53 +7018,53 @@
<source>Error retrieving metadata</source> <source>Error retrieving metadata</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">669</context> <context context-type="linenumber">666</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3456881259945295697" datatype="html"> <trans-unit id="3456881259945295697" datatype="html">
<source>Error retrieving suggestions.</source> <source>Error retrieving suggestions.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">698</context> <context context-type="linenumber">695</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="2194092841814123758" datatype="html"> <trans-unit id="2194092841814123758" datatype="html">
<source>Document &quot;<x id="PH" equiv-text="newValues.title"/>&quot; saved successfully.</source> <source>Document &quot;<x id="PH" equiv-text="newValues.title"/>&quot; saved successfully.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">870</context> <context context-type="linenumber">867</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">894</context> <context context-type="linenumber">891</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6626387786259219838" datatype="html"> <trans-unit id="6626387786259219838" datatype="html">
<source>Error saving document &quot;<x id="PH" equiv-text="this.document.title"/>&quot;</source> <source>Error saving document &quot;<x id="PH" equiv-text="this.document.title"/>&quot;</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">900</context> <context context-type="linenumber">897</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="448882439049417053" datatype="html"> <trans-unit id="448882439049417053" datatype="html">
<source>Error saving document</source> <source>Error saving document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">950</context> <context context-type="linenumber">947</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8410796510716511826" datatype="html"> <trans-unit id="8410796510716511826" datatype="html">
<source>Do you really want to move the document &quot;<x id="PH" equiv-text="this.document.title"/>&quot; to the trash?</source> <source>Do you really want to move the document &quot;<x id="PH" equiv-text="this.document.title"/>&quot; to the trash?</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">982</context> <context context-type="linenumber">979</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="282586936710748252" datatype="html"> <trans-unit id="282586936710748252" datatype="html">
<source>Documents can be restored prior to permanent deletion.</source> <source>Documents can be restored prior to permanent deletion.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">983</context> <context context-type="linenumber">980</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -7089,7 +7075,7 @@
<source>Move to trash</source> <source>Move to trash</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">985</context> <context context-type="linenumber">982</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -7100,14 +7086,14 @@
<source>Error deleting document</source> <source>Error deleting document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1004</context> <context context-type="linenumber">1001</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="619486176823357521" datatype="html"> <trans-unit id="619486176823357521" datatype="html">
<source>Reprocess confirm</source> <source>Reprocess confirm</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1024</context> <context context-type="linenumber">1021</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context> <context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
@@ -7118,81 +7104,81 @@
<source>This operation will permanently recreate the archive file for this document.</source> <source>This operation will permanently recreate the archive file for this document.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1025</context> <context context-type="linenumber">1022</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="302054111564709516" datatype="html"> <trans-unit id="302054111564709516" datatype="html">
<source>The archive file will be re-generated with the current settings.</source> <source>The archive file will be re-generated with the current settings.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1026</context> <context context-type="linenumber">1023</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="8251197608401006898" datatype="html"> <trans-unit id="8251197608401006898" datatype="html">
<source>Reprocess operation for &quot;<x id="PH" equiv-text="this.document.title"/>&quot; will begin in the background. Close and re-open or reload this document after the operation has completed to see new content.</source> <source>Reprocess operation for &quot;<x id="PH" equiv-text="this.document.title"/>&quot; will begin in the background. Close and re-open or reload this document after the operation has completed to see new content.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1036</context> <context context-type="linenumber">1033</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4409560272830824468" datatype="html"> <trans-unit id="4409560272830824468" datatype="html">
<source>Error executing operation</source> <source>Error executing operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1047</context> <context context-type="linenumber">1044</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6030453331794586802" datatype="html"> <trans-unit id="6030453331794586802" datatype="html">
<source>Error downloading document</source> <source>Error downloading document</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1096</context> <context context-type="linenumber">1093</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4458954481601077369" datatype="html"> <trans-unit id="4458954481601077369" datatype="html">
<source>Page Fit</source> <source>Page Fit</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1173</context> <context context-type="linenumber">1170</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4663705961777238777" datatype="html"> <trans-unit id="4663705961777238777" datatype="html">
<source>PDF edit operation for &quot;<x id="PH" equiv-text="this.document.title"/>&quot; will begin in the background.</source> <source>PDF edit operation for &quot;<x id="PH" equiv-text="this.document.title"/>&quot; will begin in the background.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1411</context> <context context-type="linenumber">1408</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="9043972994040261999" datatype="html"> <trans-unit id="9043972994040261999" datatype="html">
<source>Error executing PDF edit operation</source> <source>Error executing PDF edit operation</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1423</context> <context context-type="linenumber">1420</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="3740891324955700797" datatype="html"> <trans-unit id="3740891324955700797" datatype="html">
<source>Print failed.</source> <source>Print failed.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1455</context> <context context-type="linenumber">1452</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6457245677384603573" datatype="html"> <trans-unit id="6457245677384603573" datatype="html">
<source>Error loading document for printing.</source> <source>Error loading document for printing.</source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1463</context> <context context-type="linenumber">1460</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="6085793215710522488" datatype="html"> <trans-unit id="6085793215710522488" datatype="html">
<source>An error occurred loading tiff: <x id="PH" equiv-text="err.toString()"/></source> <source>An error occurred loading tiff: <x id="PH" equiv-text="err.toString()"/></source>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1528</context> <context context-type="linenumber">1525</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context> <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
<context context-type="linenumber">1532</context> <context context-type="linenumber">1529</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="4958946940233632319" datatype="html"> <trans-unit id="4958946940233632319" datatype="html">

View File

@@ -11,17 +11,17 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/cdk": "^20.2.6", "@angular/cdk": "^20.2.2",
"@angular/common": "~20.3.2", "@angular/common": "~20.2.4",
"@angular/compiler": "~20.3.2", "@angular/compiler": "~20.2.4",
"@angular/core": "~20.3.2", "@angular/core": "~20.2.4",
"@angular/forms": "~20.3.2", "@angular/forms": "~20.2.4",
"@angular/localize": "~20.3.2", "@angular/localize": "~20.2.4",
"@angular/platform-browser": "~20.3.2", "@angular/platform-browser": "~20.2.4",
"@angular/platform-browser-dynamic": "~20.3.2", "@angular/platform-browser-dynamic": "~20.2.4",
"@angular/router": "~20.3.2", "@angular/router": "~20.2.4",
"@ng-bootstrap/ng-bootstrap": "^19.0.1", "@ng-bootstrap/ng-bootstrap": "^19.0.1",
"@ng-select/ng-select": "^20.2.2", "@ng-select/ng-select": "^20.1.3",
"@ngneat/dirty-check-forms": "^3.0.3", "@ngneat/dirty-check-forms": "^3.0.3",
"@popperjs/core": "^2.11.8", "@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.8", "bootstrap": "^5.3.8",
@@ -29,48 +29,47 @@
"mime-names": "^1.0.0", "mime-names": "^1.0.0",
"ng2-pdf-viewer": "^10.4.0", "ng2-pdf-viewer": "^10.4.0",
"ngx-bootstrap-icons": "^1.9.3", "ngx-bootstrap-icons": "^1.9.3",
"ngx-color": "^10.1.0", "ngx-color": "^10.0.0",
"ngx-cookie-service": "^20.1.0", "ngx-cookie-service": "^20.1.0",
"ngx-device-detector": "^10.1.0", "ngx-device-detector": "^10.1.0",
"ngx-ui-tour-ng-bootstrap": "^17.0.1", "ngx-ui-tour-ng-bootstrap": "^17.0.1",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"utif": "^3.1.0", "utif": "^3.1.0",
"uuid": "^13.0.0", "uuid": "^11.1.0",
"zone.js": "^0.15.1" "zone.js": "^0.15.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-builders/custom-webpack": "^20.0.0", "@angular-builders/custom-webpack": "^20.0.0",
"@angular-builders/jest": "^20.0.0", "@angular-builders/jest": "^20.0.0",
"@angular-devkit/core": "^20.3.3", "@angular-devkit/core": "^20.2.2",
"@angular-devkit/schematics": "^20.3.3", "@angular-devkit/schematics": "^20.2.2",
"@angular-eslint/builder": "20.3.0", "@angular-eslint/builder": "20.2.0",
"@angular-eslint/eslint-plugin": "20.3.0", "@angular-eslint/eslint-plugin": "20.2.0",
"@angular-eslint/eslint-plugin-template": "20.3.0", "@angular-eslint/eslint-plugin-template": "20.2.0",
"@angular-eslint/schematics": "20.3.0", "@angular-eslint/schematics": "20.2.0",
"@angular-eslint/template-parser": "20.3.0", "@angular-eslint/template-parser": "20.2.0",
"@angular/build": "^20.3.3", "@angular/build": "^20.2.2",
"@angular/cli": "~20.3.3", "@angular/cli": "~20.2.2",
"@angular/compiler-cli": "~20.3.2", "@angular/compiler-cli": "~20.2.4",
"@codecov/webpack-plugin": "^1.9.1", "@codecov/webpack-plugin": "^1.9.1",
"@playwright/test": "^1.55.1", "@playwright/test": "^1.55.0",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^24.6.1", "@types/node": "^24.3.0",
"@typescript-eslint/eslint-plugin": "^8.45.0", "@typescript-eslint/eslint-plugin": "^8.41.0",
"@typescript-eslint/parser": "^8.45.0", "@typescript-eslint/parser": "^8.41.0",
"@typescript-eslint/utils": "^8.45.0", "@typescript-eslint/utils": "^8.41.0",
"eslint": "^9.36.0", "eslint": "^9.34.0",
"jest": "30.2.0", "jest": "30.1.3",
"jest-environment-jsdom": "^30.2.0", "jest-environment-jsdom": "^30.1.2",
"jest-junit": "^16.0.0", "jest-junit": "^16.0.0",
"jest-preset-angular": "^15.0.2", "jest-preset-angular": "^15.0.0",
"jest-websocket-mock": "^2.5.0", "jest-websocket-mock": "^2.5.0",
"prettier-plugin-organize-imports": "^4.3.0", "prettier-plugin-organize-imports": "^4.2.0",
"ts-node": "~10.9.1", "ts-node": "~10.9.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"webpack": "^5.102.0" "webpack": "^5.101.3"
}, },
"packageManager": "pnpm@10.17.1",
"pnpm": { "pnpm": {
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
"@parcel/watcher", "@parcel/watcher",

3494
src-ui/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -145,14 +145,4 @@ HTMLCanvasElement.prototype.getContext = <
typeof HTMLCanvasElement.prototype.getContext typeof HTMLCanvasElement.prototype.getContext
>jest.fn() >jest.fn()
jest.mock('uuid', () => ({
v4: jest.fn(() =>
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char: string) => {
const random = Math.floor(Math.random() * 16)
const value = char === 'x' ? random : (random & 0x3) | 0x8
return value.toString(16)
})
),
}))
jest.mock('pdfjs-dist') jest.mock('pdfjs-dist')

View File

@@ -16,7 +16,6 @@ import {
NgbNavItem, NgbNavItem,
} from '@ng-bootstrap/ng-bootstrap' } from '@ng-bootstrap/ng-bootstrap'
import { allIcons, NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { allIcons, NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { throwError } from 'rxjs'
import { routes } from 'src/app/app-routing.module' import { routes } from 'src/app/app-routing.module'
import { import {
PaperlessTask, PaperlessTask,
@@ -29,7 +28,6 @@ import { PermissionsGuard } from 'src/app/guards/permissions.guard'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { PermissionsService } from 'src/app/services/permissions.service' import { PermissionsService } from 'src/app/services/permissions.service'
import { TasksService } from 'src/app/services/tasks.service' import { TasksService } from 'src/app/services/tasks.service'
import { ToastService } from 'src/app/services/toast.service'
import { environment } from 'src/environments/environment' import { environment } from 'src/environments/environment'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component' import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component' import { PageHeaderComponent } from '../../common/page-header/page-header.component'
@@ -125,7 +123,6 @@ describe('TasksComponent', () => {
let router: Router let router: Router
let httpTestingController: HttpTestingController let httpTestingController: HttpTestingController
let reloadSpy let reloadSpy
let toastService: ToastService
beforeEach(async () => { beforeEach(async () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -160,7 +157,6 @@ describe('TasksComponent', () => {
httpTestingController = TestBed.inject(HttpTestingController) httpTestingController = TestBed.inject(HttpTestingController)
modalService = TestBed.inject(NgbModal) modalService = TestBed.inject(NgbModal)
router = TestBed.inject(Router) router = TestBed.inject(Router)
toastService = TestBed.inject(ToastService)
fixture = TestBed.createComponent(TasksComponent) fixture = TestBed.createComponent(TasksComponent)
component = fixture.componentInstance component = fixture.componentInstance
jest.useFakeTimers() jest.useFakeTimers()
@@ -253,42 +249,6 @@ describe('TasksComponent', () => {
expect(dismissSpy).toHaveBeenCalledWith(selected) expect(dismissSpy).toHaveBeenCalledWith(selected)
}) })
it('should show an error and re-enable modal buttons when dismissing multiple tasks fails', () => {
component.selectedTasks = new Set([tasks[0].id, tasks[1].id])
const error = new Error('dismiss failed')
const toastSpy = jest.spyOn(toastService, 'showError')
const dismissSpy = jest
.spyOn(tasksService, 'dismissTasks')
.mockReturnValue(throwError(() => error))
let modal: NgbModalRef
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
component.dismissTasks()
expect(modal).not.toBeUndefined()
modal.componentInstance.confirmClicked.emit()
expect(dismissSpy).toHaveBeenCalledWith(new Set([tasks[0].id, tasks[1].id]))
expect(toastSpy).toHaveBeenCalledWith('Error dismissing tasks', error)
expect(modal.componentInstance.buttonsEnabled).toBe(true)
expect(component.selectedTasks.size).toBe(0)
})
it('should show an error when dismissing a single task fails', () => {
const error = new Error('dismiss failed')
const toastSpy = jest.spyOn(toastService, 'showError')
const dismissSpy = jest
.spyOn(tasksService, 'dismissTasks')
.mockReturnValue(throwError(() => error))
component.dismissTask(tasks[0])
expect(dismissSpy).toHaveBeenCalledWith(new Set([tasks[0].id]))
expect(toastSpy).toHaveBeenCalledWith('Error dismissing task', error)
expect(component.selectedTasks.size).toBe(0)
})
it('should support dismiss all tasks', () => { it('should support dismiss all tasks', () => {
let modal: NgbModalRef let modal: NgbModalRef
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1])) modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))

View File

@@ -24,7 +24,6 @@ import { PaperlessTask } from 'src/app/data/paperless-task'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { TasksService } from 'src/app/services/tasks.service' import { TasksService } from 'src/app/services/tasks.service'
import { ToastService } from 'src/app/services/toast.service'
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component' import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component' import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component' import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
@@ -73,7 +72,6 @@ export class TasksComponent
tasksService = inject(TasksService) tasksService = inject(TasksService)
private modalService = inject(NgbModal) private modalService = inject(NgbModal)
private readonly router = inject(Router) private readonly router = inject(Router)
private readonly toastService = inject(ToastService)
public activeTab: TaskTab public activeTab: TaskTab
public selectedTasks: Set<number> = new Set() public selectedTasks: Set<number> = new Set()
@@ -156,19 +154,11 @@ export class TasksComponent
modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => {
modal.componentInstance.buttonsEnabled = false modal.componentInstance.buttonsEnabled = false
modal.close() modal.close()
this.tasksService.dismissTasks(tasks).subscribe({ this.tasksService.dismissTasks(tasks)
error: (e) => {
this.toastService.showError($localize`Error dismissing tasks`, e)
modal.componentInstance.buttonsEnabled = true
},
})
this.clearSelection() this.clearSelection()
}) })
} else { } else {
this.tasksService.dismissTasks(tasks).subscribe({ this.tasksService.dismissTasks(tasks)
error: (e) =>
this.toastService.showError($localize`Error dismissing task`, e),
})
this.clearSelection() this.clearSelection()
} }
} }

View File

@@ -41,3 +41,9 @@
min-width: 140px; min-width: 140px;
} }
} }
.btn-group-xs {
> .btn {
border-radius: 0.15rem;
}
}

View File

@@ -1,18 +1,19 @@
<div class="mb-3"> <div class="mb-3">
@if (title) { @if (title) {
<label class="form-label" [for]="inputId">{{title}}</label> <label [for]="inputId">{{title}}</label>
} }
<div class="input-group" [class.is-invalid]="error"> <div class="input-group" [class.is-invalid]="error">
<button type="button" class="input-group-text" [style.background-color]="value" (click)="colorPicker.toggle()">&nbsp;&nbsp;&nbsp;</button> <span class="input-group-text" [style.background-color]="value">&nbsp;&nbsp;&nbsp;</span>
<ng-template #popContent> <ng-template #popContent>
<div style="min-width: 200px;" class="pb-3"> <div style="min-width: 200px;" class="pb-3">
<color-slider [color]="value" (onChangeComplete)="colorChanged($event.color.hex)"></color-slider> <color-slider [color]="value" (onChangeComplete)="colorChanged($event.color.hex)"></color-slider>
</div> </div>
</ng-template> </ng-template>
<input #inputField class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [autoClose]="'outside'" [ngbPopover]="popContent" #colorPicker="ngbPopover" placement="bottom" popoverClass="shadow"> <input #inputField class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [autoClose]="'outside'" [ngbPopover]="popContent" placement="bottom" popoverClass="shadow">
<button class="btn btn-outline-secondary" type="button" (click)="randomize()"> <button class="btn btn-outline-secondary" type="button" (click)="randomize()">
<i-bs name="dice5"></i-bs> <i-bs name="dice5"></i-bs>

View File

@@ -42,8 +42,8 @@ describe('ColorComponent', () => {
}) })
it('should set swatch color', () => { it('should set swatch color', () => {
const swatch: HTMLButtonElement = fixture.nativeElement.querySelector( const swatch: HTMLSpanElement = fixture.nativeElement.querySelector(
'button.input-group-text' 'span.input-group-text'
) )
expect(swatch.style.backgroundColor).toEqual('') expect(swatch.style.backgroundColor).toEqual('')
component.value = '#ff0000' component.value = '#ff0000'

View File

@@ -1,10 +1,7 @@
<div class="row pt-3 pb-3 pb-md-2 align-items-center"> <div class="row pt-3 pb-3 pb-md-2 align-items-center">
<div class="col-md text-truncate"> <div class="col-md text-truncate">
<h3 class="text-truncate d-flex align-items-center" style="line-height: 1.4"> <h3 class="text-truncate" style="line-height: 1.4">
{{title}} {{title}}
@if (id) {
<span class="badge bg-primary text-primary-text-contrast ms-2 small fs-normal">ID: {{id}}</span>
}
@if (subTitle) { @if (subTitle) {
<span class="h6 mb-0 d-block d-md-inline fw-normal ms-md-3 text-truncate" style="line-height: 1.4">{{subTitle}}</span> <span class="h6 mb-0 d-block d-md-inline fw-normal ms-md-3 text-truncate" style="line-height: 1.4">{{subTitle}}</span>
} }

View File

@@ -1,10 +1,5 @@
h3 { h3 {
min-height: calc(1.325rem + 0.9vw); min-height: calc(1.325rem + 0.9vw);
.badge {
font-size: 0.65rem;
line-height: 1;
}
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {

View File

@@ -26,9 +26,6 @@ export class PageHeaderComponent {
return this._title return this._title
} }
@Input()
id: number
@Input() @Input()
subTitle: string = '' subTitle: string = ''

View File

@@ -1,4 +1,4 @@
<pngx-page-header [(title)]="title" [id]="documentId"> <pngx-page-header [(title)]="title">
@if (archiveContentRenderType === ContentRenderType.PDF && !useNativePdfViewer) { @if (archiveContentRenderType === ContentRenderType.PDF && !useNativePdfViewer) {
@if (previewNumPages) { @if (previewNumPages) {
<div class="input-group input-group-sm d-none d-md-flex"> <div class="input-group input-group-sm d-none d-md-flex">

View File

@@ -1212,7 +1212,7 @@ describe('DocumentDetailComponent', () => {
it('should support keyboard shortcuts', () => { it('should support keyboard shortcuts', () => {
initNormally() initNormally()
const hasNextSpy = jest.spyOn(component, 'hasNext').mockReturnValue(true) jest.spyOn(component, 'hasNext').mockReturnValue(true)
const nextSpy = jest.spyOn(component, 'nextDoc') const nextSpy = jest.spyOn(component, 'nextDoc')
document.dispatchEvent( document.dispatchEvent(
new KeyboardEvent('keydown', { key: 'arrowright', ctrlKey: true }) new KeyboardEvent('keydown', { key: 'arrowright', ctrlKey: true })
@@ -1226,32 +1226,21 @@ describe('DocumentDetailComponent', () => {
) )
expect(prevSpy).toHaveBeenCalled() expect(prevSpy).toHaveBeenCalled()
const isDirtySpy = jest jest.spyOn(openDocumentsService, 'isDirty').mockReturnValue(true)
.spyOn(openDocumentsService, 'isDirty')
.mockReturnValue(true)
const saveSpy = jest.spyOn(component, 'save') const saveSpy = jest.spyOn(component, 'save')
document.dispatchEvent( document.dispatchEvent(
new KeyboardEvent('keydown', { key: 's', ctrlKey: true }) new KeyboardEvent('keydown', { key: 's', ctrlKey: true })
) )
expect(saveSpy).toHaveBeenCalled() expect(saveSpy).toHaveBeenCalled()
hasNextSpy.mockReturnValue(true) jest.spyOn(openDocumentsService, 'isDirty').mockReturnValue(true)
jest.spyOn(component, 'hasNext').mockReturnValue(true)
const saveNextSpy = jest.spyOn(component, 'saveEditNext') const saveNextSpy = jest.spyOn(component, 'saveEditNext')
document.dispatchEvent( document.dispatchEvent(
new KeyboardEvent('keydown', { key: 's', ctrlKey: true, shiftKey: true }) new KeyboardEvent('keydown', { key: 's', ctrlKey: true, shiftKey: true })
) )
expect(saveNextSpy).toHaveBeenCalled() expect(saveNextSpy).toHaveBeenCalled()
saveSpy.mockClear()
saveNextSpy.mockClear()
isDirtySpy.mockReturnValue(true)
hasNextSpy.mockReturnValue(false)
document.dispatchEvent(
new KeyboardEvent('keydown', { key: 's', ctrlKey: true, shiftKey: true })
)
expect(saveNextSpy).not.toHaveBeenCalled()
expect(saveSpy).toHaveBeenCalledWith(true)
const closeSpy = jest.spyOn(component, 'close') const closeSpy = jest.spyOn(component, 'close')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'escape' })) document.dispatchEvent(new KeyboardEvent('keydown', { key: 'escape' }))
expect(closeSpy).toHaveBeenCalled() expect(closeSpy).toHaveBeenCalled()

View File

@@ -615,10 +615,7 @@ export class DocumentDetailComponent
}) })
.pipe(takeUntil(this.unsubscribeNotifier)) .pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(() => { .subscribe(() => {
if (this.openDocumentService.isDirty(this.document)) { if (this.openDocumentService.isDirty(this.document)) this.saveEditNext()
if (this.hasNext()) this.saveEditNext()
else this.save(true)
}
}) })
} }

View File

@@ -51,7 +51,7 @@ describe('TasksService', () => {
}) })
it('calls acknowledge_tasks api endpoint on dismiss and reloads', () => { it('calls acknowledge_tasks api endpoint on dismiss and reloads', () => {
tasksService.dismissTasks(new Set([1, 2, 3])).subscribe() tasksService.dismissTasks(new Set([1, 2, 3]))
const req = httpTestingController.expectOne( const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}tasks/acknowledge/` `${environment.apiBaseUrl}tasks/acknowledge/`
) )

View File

@@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http' import { HttpClient } from '@angular/common/http'
import { Injectable, inject } from '@angular/core' import { Injectable, inject } from '@angular/core'
import { Observable, Subject } from 'rxjs' import { Observable, Subject } from 'rxjs'
import { first, takeUntil, tap } from 'rxjs/operators' import { first, takeUntil } from 'rxjs/operators'
import { import {
PaperlessTask, PaperlessTask,
PaperlessTaskName, PaperlessTaskName,
@@ -68,17 +68,14 @@ export class TasksService {
} }
public dismissTasks(task_ids: Set<number>) { public dismissTasks(task_ids: Set<number>) {
return this.http this.http
.post(`${this.baseUrl}tasks/acknowledge/`, { .post(`${this.baseUrl}tasks/acknowledge/`, {
tasks: [...task_ids], tasks: [...task_ids],
}) })
.pipe( .pipe(first())
first(), .subscribe((r) => {
takeUntil(this.unsubscribeNotifer), this.reload()
tap(() => { })
this.reload()
})
)
} }
public cancelPending(): void { public cancelPending(): void {

View File

@@ -161,21 +161,3 @@ class PaperlessNotePermissions(BasePermission):
perms = self.perms_map[request.method] perms = self.perms_map[request.method]
return request.user.has_perms(perms) return request.user.has_perms(perms)
class AcknowledgeTasksPermissions(BasePermission):
"""
Permissions class that checks for model permissions for acknowledging tasks.
"""
perms_map = {
"POST": ["documents.change_paperlesstask"],
}
def has_permission(self, request, view):
if not request.user or not request.user.is_authenticated: # pragma: no cover
return False
perms = self.perms_map.get(request.method, [])
return request.user.has_perms(perms)

View File

@@ -76,9 +76,7 @@ def check_sanity(*, progress=False, scheduled=True) -> SanityCheckMessages:
messages = SanityCheckMessages() messages = SanityCheckMessages()
present_files = { present_files = {
x.resolve() x.resolve() for x in Path(settings.MEDIA_ROOT).glob("**/*") if not x.is_dir()
for x in Path(settings.MEDIA_ROOT).glob("**/*")
if not x.is_dir() and x.name not in settings.IGNORABLE_FILES
} }
lockfile = Path(settings.MEDIA_LOCK).resolve() lockfile = Path(settings.MEDIA_LOCK).resolve()

View File

@@ -135,44 +135,6 @@ class TestTasks(DirectoriesMixin, APITestCase):
response = self.client.get(self.ENDPOINT + "?acknowledged=false") response = self.client.get(self.ENDPOINT + "?acknowledged=false")
self.assertEqual(len(response.data), 0) self.assertEqual(len(response.data), 0)
def test_acknowledge_tasks_requires_change_permission(self):
"""
GIVEN:
- A regular user initially without change permissions
- A regular user with change permissions
WHEN:
- API call is made to acknowledge tasks
THEN:
- The first user is forbidden from acknowledging tasks
- The second user is allowed to acknowledge tasks
"""
regular_user = User.objects.create_user(username="test")
self.client.force_authenticate(user=regular_user)
task = PaperlessTask.objects.create(
task_id=str(uuid.uuid4()),
task_file_name="task_one.pdf",
)
response = self.client.post(
self.ENDPOINT + "acknowledge/",
{"tasks": [task.id]},
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
regular_user2 = User.objects.create_user(username="test2")
regular_user2.user_permissions.add(
Permission.objects.get(codename="change_paperlesstask"),
)
regular_user2.save()
self.client.force_authenticate(user=regular_user2)
response = self.client.post(
self.ENDPOINT + "acknowledge/",
{"tasks": [task.id]},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_tasks_owner_aware(self): def test_tasks_owner_aware(self):
""" """
GIVEN: GIVEN:

View File

@@ -169,13 +169,6 @@ class TestSanityCheck(DirectoriesMixin, TestCase):
messages = check_sanity() messages = check_sanity()
self.assertFalse(messages.has_warning) self.assertFalse(messages.has_warning)
def test_ignore_ignorable_files(self):
self.make_test_data()
Path(self.dirs.media_dir, ".DS_Store").touch()
Path(self.dirs.media_dir, "desktop.ini").touch()
messages = check_sanity()
self.assertFalse(messages.has_warning)
def test_archive_filename_no_checksum(self): def test_archive_filename_no_checksum(self):
doc = self.make_test_data() doc = self.make_test_data()
doc.archive_checksum = None doc.archive_checksum = None

View File

@@ -136,7 +136,6 @@ from documents.models import WorkflowAction
from documents.models import WorkflowTrigger from documents.models import WorkflowTrigger
from documents.parsers import get_parser_class_for_mime_type from documents.parsers import get_parser_class_for_mime_type
from documents.parsers import parse_date_generator from documents.parsers import parse_date_generator
from documents.permissions import AcknowledgeTasksPermissions
from documents.permissions import PaperlessAdminPermissions from documents.permissions import PaperlessAdminPermissions
from documents.permissions import PaperlessNotePermissions from documents.permissions import PaperlessNotePermissions
from documents.permissions import PaperlessObjectPermissions from documents.permissions import PaperlessObjectPermissions
@@ -2488,11 +2487,7 @@ class TasksViewSet(ReadOnlyModelViewSet):
queryset = PaperlessTask.objects.filter(task_id=task_id) queryset = PaperlessTask.objects.filter(task_id=task_id)
return queryset return queryset
@action( @action(methods=["post"], detail=False)
methods=["post"],
detail=False,
permission_classes=[IsAuthenticated, AcknowledgeTasksPermissions],
)
def acknowledge(self, request): def acknowledge(self, request):
serializer = AcknowledgeTasksViewSerializer(data=request.data) serializer = AcknowledgeTasksViewSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)

View File

@@ -1003,18 +1003,6 @@ THREADS_PER_WORKER = os.getenv(
# Paperless Specific Settings # # Paperless Specific Settings #
############################################################################### ###############################################################################
IGNORABLE_FILES: Final[list[str]] = [
".DS_Store",
".DS_STORE",
"._*",
".stfolder/*",
".stversions/*",
".localized/*",
"desktop.ini",
"@eaDir/*",
"Thumbs.db",
]
CONSUMER_POLLING = int(os.getenv("PAPERLESS_CONSUMER_POLLING", 0)) CONSUMER_POLLING = int(os.getenv("PAPERLESS_CONSUMER_POLLING", 0))
CONSUMER_POLLING_DELAY = int(os.getenv("PAPERLESS_CONSUMER_POLLING_DELAY", 5)) CONSUMER_POLLING_DELAY = int(os.getenv("PAPERLESS_CONSUMER_POLLING_DELAY", 5))
@@ -1037,7 +1025,7 @@ CONSUMER_IGNORE_PATTERNS = list(
json.loads( json.loads(
os.getenv( os.getenv(
"PAPERLESS_CONSUMER_IGNORE_PATTERNS", "PAPERLESS_CONSUMER_IGNORE_PATTERNS",
json.dumps(IGNORABLE_FILES), '[".DS_Store", ".DS_STORE", "._*", ".stfolder/*", ".stversions/*", ".localized/*", "desktop.ini", "@eaDir/*", "Thumbs.db"]',
), ),
), ),
) )