Compare commits

..

34 Commits

Author SHA1 Message Date
shamoon
1cd21d0f38 Fix check scheduled workflows docstring 2025-07-03 00:11:12 -07:00
Antoine Mérino
f940ed0b7b Fix: Fallback to Redis URL if no DB read cache Redis URL provided (#10315)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-07-02 10:59:24 -07:00
dependabot[bot]
3180ccf4cb Chore(deps): Bump stefanzweifel/git-auto-commit-action (#10302)
Bumps the actions group with 1 update: [stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action).


Updates `stefanzweifel/git-auto-commit-action` from 5 to 6
- [Release notes](https://github.com/stefanzweifel/git-auto-commit-action/releases)
- [Changelog](https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stefanzweifel/git-auto-commit-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: stefanzweifel/git-auto-commit-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 14:26:07 +00:00
dependabot[bot]
43abb0541b Chore(deps-dev): Bump the frontend-eslint-dependencies group across 1 directory with 4 updates (#10311)
Bumps the frontend-eslint-dependencies group with 4 updates in the /src-ui directory: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser), [@typescript-eslint/utils](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/utils) and [eslint](https://github.com/eslint/eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.35.0 to 8.35.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.35.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.35.0 to 8.35.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.35.1/packages/parser)

Updates `@typescript-eslint/utils` from 8.35.0 to 8.35.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/utils/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.35.1/packages/utils)

Updates `eslint` from 9.28.0 to 9.30.1
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.28.0...v9.30.1)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.35.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-eslint-dependencies
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.35.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-eslint-dependencies
- dependency-name: "@typescript-eslint/utils"
  dependency-version: 8.35.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-eslint-dependencies
- dependency-name: eslint
  dependency-version: 9.30.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-eslint-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 22:14:01 +00:00
dependabot[bot]
a3a405354f Chore(deps-dev): Bump @types/node from 22.15.29 to 24.0.10 in /src-ui (#10306)
---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.0.10
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 22:03:30 +00:00
dependabot[bot]
09e98d600e Chore(deps): Bump bootstrap from 5.3.6 to 5.3.7 in /src-ui (#10308)
---
updated-dependencies:
- dependency-name: bootstrap
  dependency-version: 5.3.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 21:52:26 +00:00
dependabot[bot]
01a39b9bb4 Chore(deps-dev): Bump webpack from 5.98.0 to 5.99.9 in /src-ui (#10309)
---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.99.9
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 21:39:13 +00:00
dependabot[bot]
3b0b40f071 Chore(deps-dev): Bump @playwright/test from 1.51.1 to 1.53.2 in /src-ui (#10307)
---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-version: 1.53.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 21:19:26 +00:00
GitHub Actions
6dce83865f Auto translate strings 2025-07-01 20:47:25 +00:00
dependabot[bot]
18252a19d7 Chore(deps): Bump the frontend-angular-dependencies group (#10303)
Bumps the frontend-angular-dependencies group in /src-ui with 13 updates:

| Package | From | To |
| --- | --- | --- |
| [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | `20.0.5` | `20.0.6` |
| [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | `20.0.5` | `20.0.6` |
| [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | `20.0.5` | `20.0.6` |
| [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) | `20.0.5` | `20.0.6` |
| [@angular/localize](https://github.com/angular/angular) | `20.0.5` | `20.0.6` |
| [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | `20.0.5` | `20.0.6` |
| [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) | `20.0.5` | `20.0.6` |
| [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | `20.0.5` | `20.0.6` |
| [@ng-bootstrap/ng-bootstrap](https://github.com/ng-bootstrap/ng-bootstrap) | `19.0.0` | `19.0.1` |
| [@ng-select/ng-select](https://github.com/ng-select/ng-select) | `15.1.2` | `15.1.3` |
| [ngx-cookie-service](https://github.com/stevermeister/ngx-cookie-service) | `19.1.2` | `20.0.1` |
| [ngx-device-detector](https://github.com/AhsanAyaz/ngx-device-detector) | `9.0.0` | `10.0.2` |
| [@angular/compiler-cli](https://github.com/angular/angular/tree/HEAD/packages/compiler-cli) | `20.0.5` | `20.0.6` |


Updates `@angular/common` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/common)

Updates `@angular/compiler` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/compiler)

Updates `@angular/core` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/core)

Updates `@angular/forms` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/forms)

Updates `@angular/localize` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/compare/20.0.5...20.0.6)

Updates `@angular/platform-browser` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/platform-browser)

Updates `@angular/platform-browser-dynamic` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/platform-browser-dynamic)

Updates `@angular/router` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/router)

Updates `@ng-bootstrap/ng-bootstrap` from 19.0.0 to 19.0.1
- [Release notes](https://github.com/ng-bootstrap/ng-bootstrap/releases)
- [Changelog](https://github.com/ng-bootstrap/ng-bootstrap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ng-bootstrap/ng-bootstrap/compare/19.0.0...19.0.1)

Updates `@ng-select/ng-select` from 15.1.2 to 15.1.3
- [Release notes](https://github.com/ng-select/ng-select/releases)
- [Changelog](https://github.com/ng-select/ng-select/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ng-select/ng-select/compare/v15.1.2...v15.1.3)

Updates `ngx-cookie-service` from 19.1.2 to 20.0.1
- [Release notes](https://github.com/stevermeister/ngx-cookie-service/releases)
- [Changelog](https://github.com/stevermeister/ngx-cookie-service/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stevermeister/ngx-cookie-service/compare/v19.1.2...v20.0.1)

Updates `ngx-device-detector` from 9.0.0 to 10.0.2
- [Release notes](https://github.com/AhsanAyaz/ngx-device-detector/releases)
- [Changelog](https://github.com/AhsanAyaz/ngx-device-detector/blob/master/steps-to-release.md)
- [Commits](https://github.com/AhsanAyaz/ngx-device-detector/compare/v9.0.0...v10.0.2)

Updates `@angular/compiler-cli` from 20.0.5 to 20.0.6
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/20.0.6/packages/compiler-cli)

---
updated-dependencies:
- dependency-name: "@angular/common"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/compiler"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/core"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/forms"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/localize"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/platform-browser-dynamic"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/router"
  dependency-version: 20.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@ng-bootstrap/ng-bootstrap"
  dependency-version: 19.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: "@ng-select/ng-select"
  dependency-version: 15.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
- dependency-name: ngx-cookie-service
  dependency-version: 20.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: frontend-angular-dependencies
- dependency-name: ngx-device-detector
  dependency-version: 10.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: frontend-angular-dependencies
- dependency-name: "@angular/compiler-cli"
  dependency-version: 20.0.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-angular-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 13:44:44 -07:00
Antoine Mérino
733a9674d6 Fix: prevent duplicate cachalot app in Django settings (#10300)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-07-01 09:11:58 -07:00
GitHub Actions
f3b6e15321 Auto translate strings 2025-07-01 05:59:21 +00:00
Antoine Mérino
6591d5da63 Performance: Add support for configuring date parser languages (#10181)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-07-01 05:57:38 +00:00
GitHub Actions
c974dc9400 Auto translate strings 2025-07-01 05:41:44 +00:00
Antoine Mérino
1671d49d44 Enhancement: Add a database caching for improved performance (#9784)
---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-06-30 22:36:24 -07:00
GitHub Actions
6b248ef140 Auto translate strings 2025-06-29 04:40:53 +00:00
shamoon
735681d294 Fix: correct api created coercion with timezone (#10287) 2025-06-28 21:39:14 -07:00
shamoon
a9085c65c5 Chore: fix some test warnings / errors 2025-06-27 15:03:10 -07:00
shamoon
e312425b1c Fix: reset search query for preview on reset filter (#10279) 2025-06-27 14:36:38 -07:00
GitHub Actions
13fe064f6e Auto translate strings 2025-06-27 21:08:27 +00:00
shamoon
958f98d7e5 Chore: update to Angular 20 (#10273) 2025-06-27 14:06:40 -07:00
shamoon
dfad3c4d8e Chore: clarify file deletion logging 2025-06-27 13:34:44 -07:00
shamoon
37267f3f04 Chore: add webpack directly 2025-06-22 20:03:48 -07:00
shamoon
b34538d991 Update support.yml 2025-06-22 08:03:41 -07:00
shamoon
fc97bd1315 Chore: create support discussion template 2025-06-22 08:02:26 -07:00
shamoon
dbf3721ec2 Chore: reject absurd max age values (#10243) 2025-06-22 07:39:36 -07:00
shamoon
59afbe09b1 Chore: remove PAPERLESS_DEBUG references to avoid confusion 2025-06-20 20:46:11 -07:00
shamoon
bfeaa1b119 Chore: update settings to pathlib 2025-06-20 10:50:44 -07:00
github-actions[bot]
e1c3124698 Changelog v2.17.1 - GHA (#10229) 2025-06-19 12:40:37 -07:00
shamoon
f2e22e103b Bump version to 2.17.1 2025-06-19 12:07:49 -07:00
github-actions[bot]
dda94f013e New Crowdin translations by GitHub Action (#10228)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-06-19 12:06:52 -07:00
GitHub Actions
caf00e7ead Auto translate strings 2025-06-19 18:52:01 +00:00
shamoon
f214440d2e Fix: correct PAPERLESS_EMPTY_TRASH_DIR to Path (#10227) 2025-06-19 11:50:23 -07:00
github-actions[bot]
240c9ac511 Changelog v2.17.0 - GHA (#10225) 2025-06-19 10:43:13 -07:00
216 changed files with 5960 additions and 5117 deletions

55
.github/DISCUSSION_TEMPLATE/support.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
title: "[Support] "
body:
- type: textarea
id: description
attributes:
label: What's your question or issue?
description: Provide a clear and concise description of what you're trying to do, and what's going wrong.
placeholder: |
I'm trying to...
[Include screenshots if helpful]
validations:
required: true
- type: textarea
id: steps
attributes:
label: What have you tried?
description: Describe any steps you've already taken to troubleshoot or solve the issue.
placeholder: |
- I checked the logs and saw...
- I followed the install guide and tried...
- type: input
id: version
attributes:
label: Paperless-ngx version
placeholder: e.g. 1.14.0
validations:
required: true
- type: input
id: host-os
attributes:
label: Host OS
description: Include architecture if relevant.
placeholder: e.g. Ubuntu 22.04 / Raspberry Pi arm64
- type: dropdown
id: install-method
attributes:
label: Installation method
options:
- Docker - official image
- Docker - linuxserver.io image
- Bare metal
- Other (please describe above)
- type: textarea
id: system-status
attributes:
label: System status
description: If available, copy & paste the system status output from Settings > System Status > Copy
render: json
- type: textarea
id: logs
attributes:
label: Relevant logs or output
description: If you have logs, errors that might help, paste it here.
render: bash

View File

@@ -61,7 +61,7 @@ jobs:
cd src-ui cd src-ui
pnpm run ng extract-i18n pnpm run ng extract-i18n
- name: Commit changes - name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5 uses: stefanzweifel/git-auto-commit-action@v6
with: with:
file_pattern: 'src-ui/messages.xlf src/locale/en_US/LC_MESSAGES/django.po' file_pattern: 'src-ui/messages.xlf src/locale/en_US/LC_MESSAGES/django.po'
commit_message: "Auto translate strings" commit_message: "Auto translate strings"

View File

@@ -457,6 +457,22 @@ of the index and usually makes queries faster and also ensures that the
autocompletion works properly. This command is regularly invoked by the autocompletion works properly. This command is regularly invoked by the
task scheduler. task scheduler.
### Clearing the database read cache
If the database read cache is enabled, **you must run this command** after making any changes to the database outside the application context.
This includes operations such as restoring a database backup or executing SQL statements like UPDATE, INSERT, DELETE, ALTER, CREATE, or DROP.
Failing to invalidate the cache after such modifications can lead to stale data being served from the cache, and **may cause data corruption** or inconsistent behavior in the application.
Use the following management command to clear the cache:
```
invalidate_cachalot
```
!!! info
The database read cache is based on Django-Cachalot. You can refer to their [documentation](https://django-cachalot.readthedocs.io/en/latest/quickstart.html#manage-py-command).
### Managing filenames {#renamer} ### Managing filenames {#renamer}
If you use paperless' feature to If you use paperless' feature to

View File

@@ -1,5 +1,64 @@
# Changelog # Changelog
## paperless-ngx 2.17.1
### Bug Fixes
- Fix: correct PAPERLESS_EMPTY_TRASH_DIR to Path [@shamoon](https://github.com/shamoon) ([#10227](https://github.com/paperless-ngx/paperless-ngx/pull/10227))
### All App Changes
- Fix: correct PAPERLESS_EMPTY_TRASH_DIR to Path [@shamoon](https://github.com/shamoon) ([#10227](https://github.com/paperless-ngx/paperless-ngx/pull/10227))
## paperless-ngx 2.17.0
### Breaking Changes
- Fix: restore expected pre-2.16 scheduled workflow offset behavior [@shamoon](https://github.com/shamoon) ([#10218](https://github.com/paperless-ngx/paperless-ngx/pull/10218))
### Features / Enhancements
- QoL: log version at startup, show backend vs frontend mismatch in system status [@shamoon](https://github.com/shamoon) ([#10214](https://github.com/paperless-ngx/paperless-ngx/pull/10214))
- Feature: add Persian translation [@shamoon](https://github.com/shamoon) ([#10183](https://github.com/paperless-ngx/paperless-ngx/pull/10183))
- Enhancement: support import of zipped export [@kaerbr](https://github.com/kaerbr) ([#10073](https://github.com/paperless-ngx/paperless-ngx/pull/10073))
### Bug Fixes
- Fix: more api fixes [@shamoon](https://github.com/shamoon) ([#10204](https://github.com/paperless-ngx/paperless-ngx/pull/10204))
- Fix: restore expected pre-2.16 scheduled workflow offset behavior [@shamoon](https://github.com/shamoon) ([#10218](https://github.com/paperless-ngx/paperless-ngx/pull/10218))
- Fix: fix some API crashes [@shamoon](https://github.com/shamoon) ([#10196](https://github.com/paperless-ngx/paperless-ngx/pull/10196))
- Fix: remove duplicate base path in websocket urls [@robertmx](https://github.com/robertmx) ([#10194](https://github.com/paperless-ngx/paperless-ngx/pull/10194))
- Fix: use hard delete for custom fields with workflow removal [@shamoon](https://github.com/shamoon) ([#10191](https://github.com/paperless-ngx/paperless-ngx/pull/10191))
- Fix: fix mail account test api schema [@shamoon](https://github.com/shamoon) ([#10164](https://github.com/paperless-ngx/paperless-ngx/pull/10164))
- Fix: correct api schema for mail_account process [@shamoon](https://github.com/shamoon) ([#10157](https://github.com/paperless-ngx/paperless-ngx/pull/10157))
- Fix: correct api schema for next_asn [@shamoon](https://github.com/shamoon) ([#10151](https://github.com/paperless-ngx/paperless-ngx/pull/10151))
- Fix: fix email and notes endpoints api spec [@shamoon](https://github.com/shamoon) ([#10148](https://github.com/paperless-ngx/paperless-ngx/pull/10148))
### Dependencies
- Chore: bump angular/common to 19.12.14 [@shamoon](https://github.com/shamoon) ([#10212](https://github.com/paperless-ngx/paperless-ngx/pull/10212))
### All App Changes
<details>
<summary>14 changes</summary>
- QoL: log version at startup, show backend vs frontend mismatch in system status [@shamoon](https://github.com/shamoon) ([#10214](https://github.com/paperless-ngx/paperless-ngx/pull/10214))
- Fix: more api fixes [@shamoon](https://github.com/shamoon) ([#10204](https://github.com/paperless-ngx/paperless-ngx/pull/10204))
- Fix: restore expected pre-2.16 scheduled workflow offset behavior [@shamoon](https://github.com/shamoon) ([#10218](https://github.com/paperless-ngx/paperless-ngx/pull/10218))
- Chore: switch from os.path to pathlib.Path [@gothicVI](https://github.com/gothicVI) ([#9933](https://github.com/paperless-ngx/paperless-ngx/pull/9933))
- Chore: bump angular/common to 19.12.14 [@shamoon](https://github.com/shamoon) ([#10212](https://github.com/paperless-ngx/paperless-ngx/pull/10212))
- Fix: fix some API crashes [@shamoon](https://github.com/shamoon) ([#10196](https://github.com/paperless-ngx/paperless-ngx/pull/10196))
- Fix: remove duplicate base path in websocket urls [@robertmx](https://github.com/robertmx) ([#10194](https://github.com/paperless-ngx/paperless-ngx/pull/10194))
- Fix: use hard delete for custom fields with workflow removal [@shamoon](https://github.com/shamoon) ([#10191](https://github.com/paperless-ngx/paperless-ngx/pull/10191))
- Feature: add Persian translation [@shamoon](https://github.com/shamoon) ([#10183](https://github.com/paperless-ngx/paperless-ngx/pull/10183))
- Enhancement: support import of zipped export [@kaerbr](https://github.com/kaerbr) ([#10073](https://github.com/paperless-ngx/paperless-ngx/pull/10073))
- Fix: fix mail account test api schema [@shamoon](https://github.com/shamoon) ([#10164](https://github.com/paperless-ngx/paperless-ngx/pull/10164))
- Fix: correct api schema for mail_account process [@shamoon](https://github.com/shamoon) ([#10157](https://github.com/paperless-ngx/paperless-ngx/pull/10157))
- Fix: correct api schema for next_asn [@shamoon](https://github.com/shamoon) ([#10151](https://github.com/paperless-ngx/paperless-ngx/pull/10151))
- Fix: fix email and notes endpoints api spec [@shamoon](https://github.com/shamoon) ([#10148](https://github.com/paperless-ngx/paperless-ngx/pull/10148))
</details>
## paperless-ngx 2.16.3 ## paperless-ngx 2.16.3
### Features / Enhancements ### Features / Enhancements
@@ -5948,7 +6007,6 @@ primarily.
a very good job at ocr'ing a document with the default a very good job at ocr'ing a document with the default
language. Certain language specifics such as umlauts may not get language. Certain language specifics such as umlauts may not get
picked up properly. picked up properly.
- `PAPERLESS_DEBUG` defaults to `false`.
- The presence of `PAPERLESS_DBHOST` now determines whether to use - The presence of `PAPERLESS_DBHOST` now determines whether to use
PostgreSQL or SQLite. PostgreSQL or SQLite.
- `PAPERLESS_OCR_THREADS` is gone and replaced with - `PAPERLESS_OCR_THREADS` is gone and replaced with

View File

@@ -159,6 +159,41 @@ Available options are `postgresql` and `mariadb`.
Defaults to unset, which uses Djangos built-in defaults. Defaults to unset, which uses Djangos built-in defaults.
#### [`PAPERLESS_DB_READ_CACHE_ENABLED=<bool>`](#PAPERLESS_DB_READ_CACHE_ENABLED) {#PAPERLESS_DB_READ_CACHE_ENABLED}
: Caches the database read query results into Redis. This can significantly improve application response times by caching database queries, at the cost of slightly increased memory usage.
Defaults to `false`.
!!! danger
**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**.
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}
: Specifies how long (in seconds) read data should be cached.
Allowed values are between `1` (one second) and `31536000` (one year). Defaults to `3600` (one hour).
!!! 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.
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`.
For more details, refer to the [Redis eviction policy documentation](https://redis.io/docs/latest/develop/reference/eviction/), and see the `PAPERLESS_READ_CACHE_REDIS_URL` setting to specify a separate Redis broker.
#### [`PAPERLESS_READ_CACHE_REDIS_URL=<url>`](#PAPERLESS_READ_CACHE_REDIS_URL) {#PAPERLESS_READ_CACHE_REDIS_URL}
: Defines the Redis instance used for the read cache.
Defaults to `None`.
!!! Note
If this value is not set, the same Redis instance used for scheduled tasks will be used for caching as well.
## Optional Services ## Optional Services
### Tika {#tika} ### Tika {#tika}
@@ -968,6 +1003,22 @@ still perform some basic text pre-processing before matching.
Defaults to 1. Defaults to 1.
#### [`PAPERLESS_DATE_PARSER_LANGUAGES=<lang>`](#PAPERLESS_DATE_PARSER_LANGUAGES) {#PAPERLESS_DATE_PARSER_LANGUAGES}
Specifies which language Paperless should use when parsing dates from documents.
This should be a language code supported by the dateparser library,
for example: "en", or a combination such as "en+de".
Locales are also supported (e.g., "en-AU").
Multiple languages can be combined using "+", for example: "en+de" or "en-AU+de".
For valid values, refer to the list of supported languages and locales in the [dateparser documentation](https://dateparser.readthedocs.io/en/latest/supported_locales.html).
Set this to match the languages in which most of your documents are written.
If not set, Paperless will attempt to infer the language(s) from the OCR configuration (`PAPERLESS_OCR_LANGUAGE`).
!!! note
This format differs from the `PAPERLESS_OCR_LANGUAGE` setting, which uses ISO 639-2 codes (3 letters, e.g., "eng+deu" for Tesseract OCR).
#### [`PAPERLESS_EMAIL_TASK_CRON=<cron expression>`](#PAPERLESS_EMAIL_TASK_CRON) {#PAPERLESS_EMAIL_TASK_CRON} #### [`PAPERLESS_EMAIL_TASK_CRON=<cron expression>`](#PAPERLESS_EMAIL_TASK_CRON) {#PAPERLESS_EMAIL_TASK_CRON}
: Configures the scheduled email fetching frequency. The value : Configures the scheduled email fetching frequency. The value

View File

@@ -1,10 +1,6 @@
# Have a look at the docs for documentation. # Have a look at the docs for documentation.
# https://docs.paperless-ngx.com/configuration/ # https://docs.paperless-ngx.com/configuration/
# Debug. Only enable this for development.
#PAPERLESS_DEBUG=false
# Required services # Required services
#PAPERLESS_REDIS=redis://localhost:6379 #PAPERLESS_REDIS=redis://localhost:6379

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "paperless-ngx" name = "paperless-ngx"
version = "2.17.0" version = "2.17.1"
description = "A community-supported supercharged version of paperless: scan, index and archive all your physical documents" description = "A community-supported supercharged version of paperless: scan, index and archive all your physical documents"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
@@ -26,6 +26,7 @@ dependencies = [
"django~=5.1.7", "django~=5.1.7",
"django-allauth[socialaccount,mfa]~=65.4.0", "django-allauth[socialaccount,mfa]~=65.4.0",
"django-auditlog~=3.1.2", "django-auditlog~=3.1.2",
"django-cachalot~=2.8.0",
"django-celery-results~=2.6.0", "django-celery-results~=2.6.0",
"django-compression-middleware~=0.5.0", "django-compression-middleware~=0.5.0",
"django-cors-headers~=4.7.0", "django-cors-headers~=4.7.0",
@@ -221,9 +222,6 @@ lint.per-file-ignores."src/documents/parsers.py" = [
lint.per-file-ignores."src/documents/signals/handlers.py" = [ lint.per-file-ignores."src/documents/signals/handlers.py" = [
"PTH", "PTH",
] # TODO Enable & remove ] # TODO Enable & remove
lint.per-file-ignores."src/paperless/settings.py" = [
"PTH",
] # TODO Enable & remove
lint.per-file-ignores."src/paperless_tesseract/tests/test_parser.py" = [ lint.per-file-ignores."src/paperless_tesseract/tests/test_parser.py" = [
"RUF001", "RUF001",
] ]

View File

@@ -60,10 +60,12 @@
"path": "./extra-webpack.config.ts" "path": "./extra-webpack.config.ts"
}, },
"outputPath": "dist/paperless-ui", "outputPath": "dist/paperless-ui",
"main": "src/main.ts",
"outputHashing": "none", "outputHashing": "none",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "polyfills": [
"polyfills": "src/polyfills.ts", "src/polyfills.ts"
],
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"localize": true, "localize": true,
"assets": [ "assets": [
@@ -86,12 +88,15 @@
"file-saver", "file-saver",
"utif" "utif"
], ],
"vendorChunk": true,
"extractLicenses": false, "extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true, "sourceMap": true,
"optimization": false, "optimization": false,
"namedChunks": true "namedChunks": true,
"stylePreprocessorOptions": {
"includePaths": [
"."
]
}
}, },
"configurations": { "configurations": {
"production": { "production": {
@@ -107,8 +112,6 @@
"sourceMap": false, "sourceMap": false,
"namedChunks": false, "namedChunks": false,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
@@ -188,6 +191,30 @@
}, },
"@angular-eslint/schematics:library": { "@angular-eslint/schematics:library": {
"setParserOptionsProject": true "setParserOptionsProject": true
},
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "paperless-ngx-ui", "name": "paperless-ngx-ui",
"version": "2.17.0", "version": "2.17.1",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"ng": "ng", "ng": "ng",
@@ -11,28 +11,28 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/cdk": "^19.2.14", "@angular/cdk": "^20.0.4",
"@angular/common": "~19.2.14", "@angular/common": "~20.0.6",
"@angular/compiler": "~19.2.14", "@angular/compiler": "~20.0.6",
"@angular/core": "~19.2.14", "@angular/core": "~20.0.6",
"@angular/forms": "~19.2.14", "@angular/forms": "~20.0.6",
"@angular/localize": "~19.2.14", "@angular/localize": "~20.0.6",
"@angular/platform-browser": "~19.2.14", "@angular/platform-browser": "~20.0.6",
"@angular/platform-browser-dynamic": "~19.2.14", "@angular/platform-browser-dynamic": "~20.0.6",
"@angular/router": "~19.2.14", "@angular/router": "~20.0.6",
"@ng-bootstrap/ng-bootstrap": "^18.0.0", "@ng-bootstrap/ng-bootstrap": "^19.0.1",
"@ng-select/ng-select": "^14.9.0", "@ng-select/ng-select": "^15.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.6", "bootstrap": "^5.3.7",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"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.0.0", "ngx-color": "^10.0.0",
"ngx-cookie-service": "^19.1.2", "ngx-cookie-service": "^20.0.1",
"ngx-device-detector": "^9.0.0", "ngx-device-detector": "^10.0.2",
"ngx-ui-tour-ng-bootstrap": "^16.0.0", "ngx-ui-tour-ng-bootstrap": "^17.0.0",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"utif": "^3.1.0", "utif": "^3.1.0",
@@ -40,26 +40,26 @@
"zone.js": "^0.15.1" "zone.js": "^0.15.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-builders/custom-webpack": "^19.0.1", "@angular-builders/custom-webpack": "^20.0.0",
"@angular-builders/jest": "^19.0.1", "@angular-builders/jest": "^20.0.0",
"@angular-devkit/build-angular": "^19.2.14", "@angular-devkit/core": "^20.0.4",
"@angular-devkit/core": "^19.2.14", "@angular-devkit/schematics": "^20.0.4",
"@angular-devkit/schematics": "^19.2.14", "@angular-eslint/builder": "20.1.1",
"@angular-eslint/builder": "19.7.0", "@angular-eslint/eslint-plugin": "20.1.1",
"@angular-eslint/eslint-plugin": "19.7.0", "@angular-eslint/eslint-plugin-template": "20.1.1",
"@angular-eslint/eslint-plugin-template": "19.7.0", "@angular-eslint/schematics": "20.1.1",
"@angular-eslint/schematics": "19.7.0", "@angular-eslint/template-parser": "20.1.1",
"@angular-eslint/template-parser": "19.7.0", "@angular/build": "^20.0.4",
"@angular/cli": "~19.2.14", "@angular/cli": "~20.0.4",
"@angular/compiler-cli": "~19.2.14", "@angular/compiler-cli": "~20.0.6",
"@codecov/webpack-plugin": "^1.9.1", "@codecov/webpack-plugin": "^1.9.1",
"@playwright/test": "^1.51.1", "@playwright/test": "^1.53.2",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.15.29", "@types/node": "^24.0.10",
"@typescript-eslint/eslint-plugin": "^8.33.0", "@typescript-eslint/eslint-plugin": "^8.35.1",
"@typescript-eslint/parser": "^8.33.0", "@typescript-eslint/parser": "^8.35.1",
"@typescript-eslint/utils": "^8.33.0", "@typescript-eslint/utils": "^8.35.1",
"eslint": "^9.28.0", "eslint": "^9.30.1",
"jest": "29.7.0", "jest": "29.7.0",
"jest-environment-jsdom": "^29.7.0", "jest-environment-jsdom": "^29.7.0",
"jest-junit": "^16.0.0", "jest-junit": "^16.0.0",
@@ -67,7 +67,8 @@
"jest-websocket-mock": "^2.5.0", "jest-websocket-mock": "^2.5.0",
"prettier-plugin-organize-imports": "^4.1.0", "prettier-plugin-organize-imports": "^4.1.0",
"ts-node": "~10.9.1", "ts-node": "~10.9.1",
"typescript": "^5.5.4" "typescript": "^5.8.3",
"webpack": "^5.99.9"
}, },
"pnpm": { "pnpm": {
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
@@ -77,6 +78,5 @@
"lmdb", "lmdb",
"msgpackr-extract" "msgpackr-extract"
] ]
}, }
"typings": "./src/typings.d.ts"
} }

4074
src-ui/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit, Renderer2 } from '@angular/core' import { Component, inject, OnDestroy, OnInit, Renderer2 } from '@angular/core'
import { Router, RouterOutlet } from '@angular/router' import { Router, RouterOutlet } from '@angular/router'
import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap' import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap'
import { first, Subscription } from 'rxjs' import { first, Subscription } from 'rxjs'
@@ -29,22 +29,22 @@ import { WebsocketStatusService } from './services/websocket-status.service'
], ],
}) })
export class AppComponent implements OnInit, OnDestroy { export class AppComponent implements OnInit, OnDestroy {
private settings = inject(SettingsService)
private websocketStatusService = inject(WebsocketStatusService)
private toastService = inject(ToastService)
private router = inject(Router)
private tasksService = inject(TasksService)
tourService = inject(TourService)
private renderer = inject(Renderer2)
private permissionsService = inject(PermissionsService)
private hotKeyService = inject(HotKeyService)
private componentRouterService = inject(ComponentRouterService)
newDocumentSubscription: Subscription newDocumentSubscription: Subscription
successSubscription: Subscription successSubscription: Subscription
failedSubscription: Subscription failedSubscription: Subscription
constructor( constructor() {
private settings: SettingsService,
private websocketStatusService: WebsocketStatusService,
private toastService: ToastService,
private router: Router,
private tasksService: TasksService,
public tourService: TourService,
private renderer: Renderer2,
private permissionsService: PermissionsService,
private hotKeyService: HotKeyService,
private componentRouterService: ComponentRouterService
) {
let anyWindow = window as any let anyWindow = window as any
anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.mjs' anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.mjs'
this.settings.updateAppearanceSettings() this.settings.updateAppearanceSettings()

View File

@@ -1,5 +1,5 @@
import { AsyncPipe } from '@angular/common' import { AsyncPipe } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { import {
AbstractControl, AbstractControl,
FormControl, FormControl,
@@ -57,6 +57,10 @@ export class ConfigComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit, OnDestroy, DirtyComponent implements OnInit, OnDestroy, DirtyComponent
{ {
private configService = inject(ConfigService)
private toastService = inject(ToastService)
private settingsService = inject(SettingsService)
public readonly ConfigOptionType = ConfigOptionType public readonly ConfigOptionType = ConfigOptionType
// generated dynamically // generated dynamically
@@ -77,11 +81,7 @@ export class ConfigComponent
storeSub: Subscription storeSub: Subscription
isDirty$: Observable<boolean> isDirty$: Observable<boolean>
constructor( constructor() {
private configService: ConfigService,
private toastService: ToastService,
private settingsService: SettingsService
) {
super() super()
this.configForm.addControl('id', new FormControl()) this.configForm.addControl('id', new FormControl())
PaperlessConfigOptions.forEach((option) => { PaperlessConfigOptions.forEach((option) => {

View File

@@ -5,6 +5,7 @@ import {
OnDestroy, OnDestroy,
OnInit, OnInit,
ViewChild, ViewChild,
inject,
} from '@angular/core' } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap' import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'
@@ -28,12 +29,8 @@ export class LogsComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
constructor( private logService = inject(LogService)
private logService: LogService, private changedetectorRef = inject(ChangeDetectorRef)
private changedetectorRef: ChangeDetectorRef
) {
super()
}
public logs: string[] = [] public logs: string[] = []

View File

@@ -2,10 +2,10 @@ import { AsyncPipe, ViewportScroller } from '@angular/common'
import { import {
AfterViewInit, AfterViewInit,
Component, Component,
Inject,
LOCALE_ID, LOCALE_ID,
OnDestroy, OnDestroy,
OnInit, OnInit,
inject,
} from '@angular/core' } from '@angular/core'
import { import {
FormControl, FormControl,
@@ -104,6 +104,20 @@ export class SettingsComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, AfterViewInit, OnDestroy, DirtyComponent implements OnInit, AfterViewInit, OnDestroy, DirtyComponent
{ {
private documentListViewService = inject(DocumentListViewService)
private toastService = inject(ToastService)
private settings = inject(SettingsService)
currentLocale = inject(LOCALE_ID)
private viewportScroller = inject(ViewportScroller)
private activatedRoute = inject(ActivatedRoute)
readonly tourService = inject(TourService)
private usersService = inject(UserService)
private groupsService = inject(GroupService)
private router = inject(Router)
permissionsService = inject(PermissionsService)
private modalService = inject(NgbModal)
private systemStatusService = inject(SystemStatusService)
activeNavID: number activeNavID: number
settingsForm = new FormGroup({ settingsForm = new FormGroup({
@@ -179,21 +193,7 @@ export class SettingsComponent
) )
} }
constructor( constructor() {
private documentListViewService: DocumentListViewService,
private toastService: ToastService,
private settings: SettingsService,
@Inject(LOCALE_ID) public currentLocale: string,
private viewportScroller: ViewportScroller,
private activatedRoute: ActivatedRoute,
public readonly tourService: TourService,
private usersService: UserService,
private groupsService: GroupService,
private router: Router,
public permissionsService: PermissionsService,
private modalService: NgbModal,
private systemStatusService: SystemStatusService
) {
super() super()
this.settings.settingsSaved.subscribe(() => { this.settings.settingsSaved.subscribe(() => {
if (!this.savePending) this.initialize() if (!this.savePending) this.initialize()

View File

@@ -1,5 +1,5 @@
import { NgTemplateOutlet, SlicePipe } from '@angular/common' import { NgTemplateOutlet, SlicePipe } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, inject, OnDestroy, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { import {
@@ -69,6 +69,10 @@ export class TasksComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
tasksService = inject(TasksService)
private modalService = inject(NgbModal)
private readonly router = inject(Router)
public activeTab: TaskTab public activeTab: TaskTab
public selectedTasks: Set<number> = new Set() public selectedTasks: Set<number> = new Set()
public togggleAll: boolean = false public togggleAll: boolean = false
@@ -105,14 +109,6 @@ export class TasksComponent
: $localize`Dismiss all` : $localize`Dismiss all`
} }
constructor(
public tasksService: TasksService,
private modalService: NgbModal,
private readonly router: Router
) {
super()
}
ngOnInit() { ngOnInit() {
this.tasksService.reload() this.tasksService.reload()
timer(5000, 5000) timer(5000, 5000)

View File

@@ -1,4 +1,4 @@
import { Component, OnDestroy } from '@angular/core' import { Component, OnDestroy, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { import {
@@ -36,19 +36,19 @@ export class TrashComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnDestroy implements OnDestroy
{ {
private trashService = inject(TrashService)
private toastService = inject(ToastService)
private modalService = inject(NgbModal)
private settingsService = inject(SettingsService)
private router = inject(Router)
public documentsInTrash: Document[] = [] public documentsInTrash: Document[] = []
public selectedDocuments: Set<number> = new Set() public selectedDocuments: Set<number> = new Set()
public allToggled: boolean = false public allToggled: boolean = false
public page: number = 1 public page: number = 1
public totalDocuments: number public totalDocuments: number
constructor( constructor() {
private trashService: TrashService,
private toastService: ToastService,
private modalService: NgbModal,
private settingsService: SettingsService,
private router: Router
) {
super() super()
this.reload() this.reload()
} }

View File

@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Subject, first, takeUntil } from 'rxjs' import { Subject, first, takeUntil } from 'rxjs'
@@ -31,22 +31,18 @@ export class UsersAndGroupsComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
private usersService = inject(UserService)
private groupsService = inject(GroupService)
private toastService = inject(ToastService)
private modalService = inject(NgbModal)
permissionsService = inject(PermissionsService)
private settings = inject(SettingsService)
users: User[] users: User[]
groups: Group[] groups: Group[]
unsubscribeNotifier: Subject<any> = new Subject() unsubscribeNotifier: Subject<any> = new Subject()
constructor(
private usersService: UserService,
private groupsService: GroupService,
private toastService: ToastService,
private modalService: NgbModal,
public permissionsService: PermissionsService,
private settings: SettingsService
) {
super()
}
ngOnInit(): void { ngOnInit(): void {
this.usersService this.usersService
.listAll(null, null, { full_perms: true }) .listAll(null, null, { full_perms: true })

View File

@@ -6,7 +6,7 @@ import {
moveItemInArray, moveItemInArray,
} from '@angular/cdk/drag-drop' } from '@angular/cdk/drag-drop'
import { NgClass } from '@angular/common' import { NgClass } from '@angular/common'
import { Component, HostListener, OnInit } from '@angular/core' import { Component, HostListener, inject, OnInit } from '@angular/core'
import { ActivatedRoute, Router, RouterModule } from '@angular/router' import { ActivatedRoute, Router, RouterModule } from '@angular/router'
import { import {
NgbCollapseModule, NgbCollapseModule,
@@ -74,26 +74,27 @@ export class AppFrameComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, ComponentCanDeactivate implements OnInit, ComponentCanDeactivate
{ {
router = inject(Router)
private activatedRoute = inject(ActivatedRoute)
private openDocumentsService = inject(OpenDocumentsService)
savedViewService = inject(SavedViewService)
private remoteVersionService = inject(RemoteVersionService)
settingsService = inject(SettingsService)
tasksService = inject(TasksService)
private readonly toastService = inject(ToastService)
private modalService = inject(NgbModal)
permissionsService = inject(PermissionsService)
private djangoMessagesService = inject(DjangoMessagesService)
appRemoteVersion: AppRemoteVersion appRemoteVersion: AppRemoteVersion
isMenuCollapsed: boolean = true isMenuCollapsed: boolean = true
slimSidebarAnimating: boolean = false slimSidebarAnimating: boolean = false
constructor( constructor() {
public router: Router,
private activatedRoute: ActivatedRoute,
private openDocumentsService: OpenDocumentsService,
public savedViewService: SavedViewService,
private remoteVersionService: RemoteVersionService,
public settingsService: SettingsService,
public tasksService: TasksService,
private readonly toastService: ToastService,
private modalService: NgbModal,
public permissionsService: PermissionsService,
private djangoMessagesService: DjangoMessagesService
) {
super() super()
const permissionsService = this.permissionsService
if ( if (
permissionsService.currentUserCan( permissionsService.currentUserCan(

View File

@@ -6,6 +6,7 @@ import {
QueryList, QueryList,
ViewChild, ViewChild,
ViewChildren, ViewChildren,
inject,
} from '@angular/core' } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router' import { Router } from '@angular/router'
@@ -69,6 +70,17 @@ import { WorkflowEditDialogComponent } from '../../common/edit-dialog/workflow-e
], ],
}) })
export class GlobalSearchComponent implements OnInit { export class GlobalSearchComponent implements OnInit {
searchService = inject(SearchService)
private router = inject(Router)
private modalService = inject(NgbModal)
private documentService = inject(DocumentService)
private documentListViewService = inject(DocumentListViewService)
private permissionsService = inject(PermissionsService)
private toastService = inject(ToastService)
private hotkeyService = inject(HotKeyService)
private settingsService = inject(SettingsService)
private locationStrategy = inject(LocationStrategy)
public DataType = DataType public DataType = DataType
public query: string public query: string
public queryDebounce: Subject<string> public queryDebounce: Subject<string>
@@ -90,18 +102,7 @@ export class GlobalSearchComponent implements OnInit {
) )
} }
constructor( constructor() {
public searchService: SearchService,
private router: Router,
private modalService: NgbModal,
private documentService: DocumentService,
private documentListViewService: DocumentListViewService,
private permissionsService: PermissionsService,
private toastService: ToastService,
private hotkeyService: HotKeyService,
private settingsService: SettingsService,
private locationStrategy: LocationStrategy
) {
this.queryDebounce = new Subject<string>() this.queryDebounce = new Subject<string>()
this.queryDebounce this.queryDebounce

View File

@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { import {
NgbDropdownModule, NgbDropdownModule,
NgbProgressbarModule, NgbProgressbarModule,
@@ -20,7 +20,7 @@ import { ToastComponent } from '../../common/toast/toast.component'
], ],
}) })
export class ToastsDropdownComponent implements OnInit, OnDestroy { export class ToastsDropdownComponent implements OnInit, OnDestroy {
constructor(public toastService: ToastService) {} toastService = inject(ToastService)
private subscription: Subscription private subscription: Subscription

View File

@@ -1,5 +1,5 @@
import { DecimalPipe } from '@angular/common' import { DecimalPipe } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core' import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Subject } from 'rxjs' import { Subject } from 'rxjs'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe' import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
@@ -12,9 +12,7 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
imports: [DecimalPipe, SafeHtmlPipe], imports: [DecimalPipe, SafeHtmlPipe],
}) })
export class ConfirmDialogComponent extends LoadingComponentWithPermissions { export class ConfirmDialogComponent extends LoadingComponentWithPermissions {
constructor(public activeModal: NgbActiveModal) { activeModal = inject(NgbActiveModal)
super()
}
@Output() @Output()
public confirmClicked = new EventEmitter() public confirmClicked = new EventEmitter()

View File

@@ -1,6 +1,5 @@
import { Component, TemplateRef, ViewChild } from '@angular/core' import { Component, TemplateRef, ViewChild, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { import {
PDFDocumentProxy, PDFDocumentProxy,
PdfViewerComponent, PdfViewerComponent,
@@ -17,6 +16,8 @@ import { ConfirmDialogComponent } from '../confirm-dialog.component'
imports: [PdfViewerModule, FormsModule, ReactiveFormsModule, SafeHtmlPipe], imports: [PdfViewerModule, FormsModule, ReactiveFormsModule, SafeHtmlPipe],
}) })
export class DeletePagesConfirmDialogComponent extends ConfirmDialogComponent { export class DeletePagesConfirmDialogComponent extends ConfirmDialogComponent {
private documentService = inject(DocumentService)
public documentID: number public documentID: number
public pages: number[] = [] public pages: number[] = []
public currentPage: number = 1 public currentPage: number = 1
@@ -34,11 +35,8 @@ export class DeletePagesConfirmDialogComponent extends ConfirmDialogComponent {
return this.documentService.getPreviewUrl(this.documentID) return this.documentService.getPreviewUrl(this.documentID)
} }
constructor( constructor() {
activeModal: NgbActiveModal, super()
private documentService: DocumentService
) {
super(activeModal)
} }
public pdfPreviewLoaded(pdf: PDFDocumentProxy) { public pdfPreviewLoaded(pdf: PDFDocumentProxy) {

View File

@@ -3,9 +3,8 @@ import {
DragDropModule, DragDropModule,
moveItemInArray, moveItemInArray,
} from '@angular/cdk/drag-drop' } from '@angular/cdk/drag-drop'
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { takeUntil } from 'rxjs' import { takeUntil } from 'rxjs'
import { Document } from 'src/app/data/document' import { Document } from 'src/app/data/document'
@@ -28,6 +27,9 @@ export class MergeConfirmDialogComponent
extends ConfirmDialogComponent extends ConfirmDialogComponent
implements OnInit implements OnInit
{ {
private documentService = inject(DocumentService)
private permissionService = inject(PermissionsService)
public documentIDs: number[] = [] public documentIDs: number[] = []
public archiveFallback: boolean = false public archiveFallback: boolean = false
public deleteOriginals: boolean = false public deleteOriginals: boolean = false
@@ -38,12 +40,8 @@ export class MergeConfirmDialogComponent
public metadataDocumentID: number = -1 public metadataDocumentID: number = -1
constructor( constructor() {
activeModal: NgbActiveModal, super()
private documentService: DocumentService,
private permissionService: PermissionsService
) {
super(activeModal)
} }
ngOnInit() { ngOnInit() {

View File

@@ -1,6 +1,5 @@
import { NgStyle } from '@angular/common' import { NgStyle } from '@angular/common'
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe' import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { DocumentService } from 'src/app/services/rest/document.service' import { DocumentService } from 'src/app/services/rest/document.service'
@@ -13,6 +12,8 @@ import { ConfirmDialogComponent } from '../confirm-dialog.component'
imports: [NgStyle, NgxBootstrapIconsModule, SafeHtmlPipe], imports: [NgStyle, NgxBootstrapIconsModule, SafeHtmlPipe],
}) })
export class RotateConfirmDialogComponent extends ConfirmDialogComponent { export class RotateConfirmDialogComponent extends ConfirmDialogComponent {
documentService = inject(DocumentService)
public documentID: number public documentID: number
public showPDFNote: boolean = true public showPDFNote: boolean = true
@@ -25,11 +26,8 @@ export class RotateConfirmDialogComponent extends ConfirmDialogComponent {
return degrees return degrees
} }
constructor( constructor() {
activeModal: NgbActiveModal, super()
public documentService: DocumentService
) {
super(activeModal)
} }
rotate(clockwise: boolean = true) { rotate(clockwise: boolean = true) {

View File

@@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { PDFDocumentProxy, PdfViewerModule } from 'ng2-pdf-viewer' import { PDFDocumentProxy, PdfViewerModule } from 'ng2-pdf-viewer'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Document } from 'src/app/data/document' import { Document } from 'src/app/data/document'
@@ -23,6 +22,9 @@ export class SplitConfirmDialogComponent
extends ConfirmDialogComponent extends ConfirmDialogComponent
implements OnInit implements OnInit
{ {
private documentService = inject(DocumentService)
private permissionService = inject(PermissionsService)
public get pagesString(): string { public get pagesString(): string {
let pagesStr = '' let pagesStr = ''
@@ -62,12 +64,8 @@ export class SplitConfirmDialogComponent
return this.documentService.getPreviewUrl(this.documentID) return this.documentService.getPreviewUrl(this.documentID)
} }
constructor( constructor() {
activeModal: NgbActiveModal, super()
private documentService: DocumentService,
private permissionService: PermissionsService
) {
super(activeModal)
this.confirmButtonEnabled = this.pages.size > 0 this.confirmButtonEnabled = this.pages.size > 0
} }

View File

@@ -1,5 +1,5 @@
import { CurrencyPipe, getLocaleCurrencyCode } from '@angular/common' import { CurrencyPipe, getLocaleCurrencyCode } from '@angular/common'
import { Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core' import { Component, Input, LOCALE_ID, OnInit, inject } from '@angular/core'
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap' import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { takeUntil } from 'rxjs' import { takeUntil } from 'rxjs'
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field' import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
@@ -20,6 +20,9 @@ export class CustomFieldDisplayComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit implements OnInit
{ {
private customFieldService = inject(CustomFieldsService)
private documentService = inject(DocumentService)
CustomFieldDataType = CustomFieldDataType CustomFieldDataType = CustomFieldDataType
private _document: Document private _document: Document
@@ -63,11 +66,9 @@ export class CustomFieldDisplayComponent
private defaultCurrencyCode: any private defaultCurrencyCode: any
constructor( constructor() {
private customFieldService: CustomFieldsService, const currentLocale = inject(LOCALE_ID)
private documentService: DocumentService,
@Inject(LOCALE_ID) currentLocale: string
) {
super() super()
this.defaultCurrencyCode = getLocaleCurrencyCode(currentLocale) this.defaultCurrencyCode = getLocaleCurrencyCode(currentLocale)
this.customFieldService.listAll().subscribe((r) => { this.customFieldService.listAll().subscribe((r) => {

View File

@@ -7,6 +7,7 @@ import {
QueryList, QueryList,
ViewChild, ViewChild,
ViewChildren, ViewChildren,
inject,
} from '@angular/core' } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap'
@@ -37,6 +38,11 @@ import { CustomFieldEditDialogComponent } from '../edit-dialog/custom-field-edit
], ],
}) })
export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissions { export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissions {
private customFieldsService = inject(CustomFieldsService)
private modalService = inject(NgbModal)
private toastService = inject(ToastService)
private permissionsService = inject(PermissionsService)
public popperOptions = pngxPopperOptions public popperOptions = pngxPopperOptions
@Input() @Input()
@@ -78,12 +84,7 @@ export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissio
) )
} }
constructor( constructor() {
private customFieldsService: CustomFieldsService,
private modalService: NgbModal,
private toastService: ToastService,
private permissionsService: PermissionsService
) {
super() super()
this.getFields() this.getFields()
} }

View File

@@ -2,6 +2,7 @@ import { NgTemplateOutlet } from '@angular/common'
import { import {
Component, Component,
EventEmitter, EventEmitter,
inject,
Input, Input,
Output, Output,
QueryList, QueryList,
@@ -178,6 +179,8 @@ export class CustomFieldQueriesModel {
], ],
}) })
export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPermissions { export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPermissions {
protected customFieldsService = inject(CustomFieldsService)
public CustomFieldQueryComponentType = CustomFieldQueryElementType public CustomFieldQueryComponentType = CustomFieldQueryElementType
public CustomFieldQueryOperator = CustomFieldQueryOperator public CustomFieldQueryOperator = CustomFieldQueryOperator
public CustomFieldDataType = CustomFieldDataType public CustomFieldDataType = CustomFieldDataType
@@ -245,7 +248,7 @@ export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPerm
public readonly today: string = new Date().toISOString().split('T')[0] public readonly today: string = new Date().toISOString().split('T')[0]
constructor(protected customFieldsService: CustomFieldsService) { constructor() {
super() super()
this.selectionModel = new CustomFieldQueriesModel() this.selectionModel = new CustomFieldQueriesModel()
this.getFields() this.getFields()

View File

@@ -6,6 +6,7 @@ import {
OnDestroy, OnDestroy,
OnInit, OnInit,
Output, Output,
inject,
} from '@angular/core' } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { import {
@@ -63,7 +64,9 @@ export enum RelativeDate {
export class DatesDropdownComponent implements OnInit, OnDestroy { export class DatesDropdownComponent implements OnInit, OnDestroy {
public popperOptions = pngxPopperOptions public popperOptions = pngxPopperOptions
constructor(settings: SettingsService) { constructor() {
const settings = inject(SettingsService)
this.datePlaceHolder = settings.getLocalizedDateInputFormat() this.datePlaceHolder = settings.getLocalizedDateInputFormat()
} }

View File

@@ -13,8 +13,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select> <pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) { @if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text> <pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></pngx-input-check> <pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></pngx-input-check>
} }

View File

@@ -1,11 +1,10 @@
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Correspondent } from 'src/app/data/correspondent' import { Correspondent } from 'src/app/data/correspondent'
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
@@ -13,6 +12,7 @@ import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
import { CorrespondentService } from 'src/app/services/rest/correspondent.service' import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
import { UserService } from 'src/app/services/rest/user.service' import { UserService } from 'src/app/services/rest/user.service'
import { SettingsService } from 'src/app/services/settings.service' import { SettingsService } from 'src/app/services/settings.service'
import { CheckComponent } from '../../input/check/check.component'
import { PermissionsFormComponent } from '../../input/permissions/permissions-form/permissions-form.component' import { PermissionsFormComponent } from '../../input/permissions/permissions-form/permissions-form.component'
import { SelectComponent } from '../../input/select/select.component' import { SelectComponent } from '../../input/select/select.component'
import { TextComponent } from '../../input/text/text.component' import { TextComponent } from '../../input/text/text.component'
@@ -22,6 +22,7 @@ import { TextComponent } from '../../input/text/text.component'
templateUrl: './correspondent-edit-dialog.component.html', templateUrl: './correspondent-edit-dialog.component.html',
styleUrls: ['./correspondent-edit-dialog.component.scss'], styleUrls: ['./correspondent-edit-dialog.component.scss'],
imports: [ imports: [
CheckComponent,
SelectComponent, SelectComponent,
PermissionsFormComponent, PermissionsFormComponent,
TextComponent, TextComponent,
@@ -31,13 +32,11 @@ import { TextComponent } from '../../input/text/text.component'
], ],
}) })
export class CorrespondentEditDialogComponent extends EditDialogComponent<Correspondent> { export class CorrespondentEditDialogComponent extends EditDialogComponent<Correspondent> {
constructor( constructor() {
service: CorrespondentService, super()
activeModal: NgbActiveModal, this.service = inject(CorrespondentService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService this.settingsService = inject(SettingsService)
) {
super(service, activeModal, userService, settingsService)
} }
getCreateTitle() { getCreateTitle() {

View File

@@ -5,6 +5,7 @@ import {
OnInit, OnInit,
QueryList, QueryList,
ViewChildren, ViewChildren,
inject,
} from '@angular/core' } from '@angular/core'
import { import {
FormArray, FormArray,
@@ -13,7 +14,6 @@ import {
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { takeUntil } from 'rxjs' import { takeUntil } from 'rxjs'
import { import {
@@ -54,13 +54,11 @@ export class CustomFieldEditDialogComponent
.select_options as FormArray .select_options as FormArray
} }
constructor( constructor() {
service: CustomFieldsService, super()
activeModal: NgbActiveModal, this.service = inject(CustomFieldsService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService this.settingsService = inject(SettingsService)
) {
super(service, activeModal, userService, settingsService)
} }
ngOnInit(): void { ngOnInit(): void {

View File

@@ -14,8 +14,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select> <pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) { @if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text> <pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check> <pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
} }
</div> </div>

View File

@@ -1,11 +1,10 @@
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { DocumentType } from 'src/app/data/document-type' import { DocumentType } from 'src/app/data/document-type'
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
@@ -13,6 +12,7 @@ import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
import { DocumentTypeService } from 'src/app/services/rest/document-type.service' import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
import { UserService } from 'src/app/services/rest/user.service' import { UserService } from 'src/app/services/rest/user.service'
import { SettingsService } from 'src/app/services/settings.service' import { SettingsService } from 'src/app/services/settings.service'
import { CheckComponent } from '../../input/check/check.component'
import { PermissionsFormComponent } from '../../input/permissions/permissions-form/permissions-form.component' import { PermissionsFormComponent } from '../../input/permissions/permissions-form/permissions-form.component'
import { SelectComponent } from '../../input/select/select.component' import { SelectComponent } from '../../input/select/select.component'
import { TextComponent } from '../../input/text/text.component' import { TextComponent } from '../../input/text/text.component'
@@ -22,6 +22,7 @@ import { TextComponent } from '../../input/text/text.component'
templateUrl: './document-type-edit-dialog.component.html', templateUrl: './document-type-edit-dialog.component.html',
styleUrls: ['./document-type-edit-dialog.component.scss'], styleUrls: ['./document-type-edit-dialog.component.scss'],
imports: [ imports: [
CheckComponent,
SelectComponent, SelectComponent,
PermissionsFormComponent, PermissionsFormComponent,
TextComponent, TextComponent,
@@ -31,13 +32,11 @@ import { TextComponent } from '../../input/text/text.component'
], ],
}) })
export class DocumentTypeEditDialogComponent extends EditDialogComponent<DocumentType> { export class DocumentTypeEditDialogComponent extends EditDialogComponent<DocumentType> {
constructor( constructor() {
service: DocumentTypeService, super()
activeModal: NgbActiveModal, this.service = inject(DocumentTypeService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService this.settingsService = inject(SettingsService)
) {
super(service, activeModal, userService, settingsService)
} }
getCreateTitle() { getCreateTitle() {

View File

@@ -41,13 +41,9 @@ import { EditDialogComponent, EditDialogMode } from './edit-dialog.component'
imports: [FormsModule, ReactiveFormsModule], imports: [FormsModule, ReactiveFormsModule],
}) })
class TestComponent extends EditDialogComponent<Tag> { class TestComponent extends EditDialogComponent<Tag> {
constructor( constructor() {
service: TagService, super()
activeModal: NgbActiveModal, this.service = TestBed.inject(TagService)
userService: UserService,
settingsService: SettingsService
) {
super(service, activeModal, userService, settingsService)
} }
getForm(): FormGroup<any> { getForm(): FormGroup<any> {

View File

@@ -1,4 +1,11 @@
import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core' import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
inject,
} from '@angular/core'
import { FormGroup } from '@angular/forms' import { FormGroup } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { Observable } from 'rxjs' import { Observable } from 'rxjs'
@@ -29,14 +36,12 @@ export abstract class EditDialogComponent<
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit implements OnInit
{ {
constructor( protected service = inject<AbstractPaperlessService<T>>(
protected service: AbstractPaperlessService<T>, AbstractPaperlessService
private activeModal: NgbActiveModal, )
private userService: UserService, protected activeModal = inject(NgbActiveModal)
protected settingsService: SettingsService protected userService = inject(UserService)
) { protected settingsService = inject(SettingsService)
super()
}
users: User[] users: User[]

View File

@@ -1,11 +1,10 @@
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Group } from 'src/app/data/group' import { Group } from 'src/app/data/group'
import { GroupService } from 'src/app/services/rest/group.service' import { GroupService } from 'src/app/services/rest/group.service'
@@ -26,13 +25,11 @@ import { PermissionsSelectComponent } from '../../permissions-select/permissions
], ],
}) })
export class GroupEditDialogComponent extends EditDialogComponent<Group> { export class GroupEditDialogComponent extends EditDialogComponent<Group> {
constructor( constructor() {
service: GroupService, super()
activeModal: NgbActiveModal, this.service = inject(GroupService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService this.settingsService = inject(SettingsService)
) {
super(service, activeModal, userService, settingsService)
} }
getCreateTitle() { getCreateTitle() {

View File

@@ -1,15 +1,11 @@
import { Component, ViewChild } from '@angular/core' import { Component, ViewChild, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { import { NgbAlert, NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'
NgbActiveModal,
NgbAlert,
NgbAlertModule,
} from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { IMAPSecurity, MailAccount } from 'src/app/data/mail-account' import { IMAPSecurity, MailAccount } from 'src/app/data/mail-account'
import { MailAccountService } from 'src/app/services/rest/mail-account.service' import { MailAccountService } from 'src/app/services/rest/mail-account.service'
@@ -47,13 +43,11 @@ export class MailAccountEditDialogComponent extends EditDialogComponent<MailAcco
@ViewChild('testResultAlert', { static: false }) testResultAlert: NgbAlert @ViewChild('testResultAlert', { static: false }) testResultAlert: NgbAlert
constructor( constructor() {
service: MailAccountService, super()
activeModal: NgbActiveModal, this.service = inject(MailAccountService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService this.settingsService = inject(SettingsService)
) {
super(service, activeModal, userService, settingsService)
} }
getCreateTitle() { getCreateTitle() {

View File

@@ -1,11 +1,10 @@
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { first } from 'rxjs' import { first } from 'rxjs'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Correspondent } from 'src/app/data/correspondent' import { Correspondent } from 'src/app/data/correspondent'
@@ -155,32 +154,34 @@ const METADATA_CORRESPONDENT_OPTIONS = [
], ],
}) })
export class MailRuleEditDialogComponent extends EditDialogComponent<MailRule> { export class MailRuleEditDialogComponent extends EditDialogComponent<MailRule> {
private accountService: MailAccountService
private correspondentService: CorrespondentService
private documentTypeService: DocumentTypeService
accounts: MailAccount[] accounts: MailAccount[]
correspondents: Correspondent[] correspondents: Correspondent[]
documentTypes: DocumentType[] documentTypes: DocumentType[]
constructor( constructor() {
service: MailRuleService, super()
activeModal: NgbActiveModal, this.service = inject(MailRuleService)
accountService: MailAccountService, this.accountService = inject(MailAccountService)
correspondentService: CorrespondentService, this.correspondentService = inject(CorrespondentService)
documentTypeService: DocumentTypeService, this.documentTypeService = inject(DocumentTypeService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService this.settingsService = inject(SettingsService)
) {
super(service, activeModal, userService, settingsService)
accountService this.accountService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.accounts = result.results)) .subscribe((result) => (this.accounts = result.results))
correspondentService this.correspondentService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.correspondents = result.results)) .subscribe((result) => (this.correspondents = result.results))
documentTypeService this.documentTypeService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.documentTypes = result.results)) .subscribe((result) => (this.documentTypes = result.results))

View File

@@ -64,8 +64,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select> <pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) { @if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text> <pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check> <pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
} }

View File

@@ -1,12 +1,12 @@
import { AsyncPipe, NgTemplateOutlet } from '@angular/common' import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
import { Component, OnDestroy } from '@angular/core' import { Component, OnDestroy, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbAccordionModule, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'
import { NgSelectComponent } from '@ng-select/ng-select' import { NgSelectComponent } from '@ng-select/ng-select'
import { import {
Observable, Observable,
@@ -60,6 +60,8 @@ export class StoragePathEditDialogComponent
extends EditDialogComponent<StoragePath> extends EditDialogComponent<StoragePath>
implements OnDestroy implements OnDestroy
{ {
private documentsService = inject(DocumentService)
public documentsInput$ = new Subject<string>() public documentsInput$ = new Subject<string>()
public foundDocuments$: Observable<Document[]> public foundDocuments$: Observable<Document[]>
private testDocument: Document private testDocument: Document
@@ -68,14 +70,11 @@ export class StoragePathEditDialogComponent
public loading = false public loading = false
public testLoading = false public testLoading = false
constructor( constructor() {
service: StoragePathService, super()
activeModal: NgbActiveModal, this.service = inject(StoragePathService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService, this.settingsService = inject(SettingsService)
private documentsService: DocumentService
) {
super(service, activeModal, userService, settingsService)
this.initPathObservables() this.initPathObservables()
} }

View File

@@ -16,8 +16,6 @@
<pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select> <pngx-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
@if (patternRequired) { @if (patternRequired) {
<pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text> <pngx-input-text i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
}
@if (patternRequired) {
<pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check> <pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
} }

View File

@@ -1,11 +1,10 @@
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
import { Tag } from 'src/app/data/tag' import { Tag } from 'src/app/data/tag'
@@ -36,13 +35,11 @@ import { TextComponent } from '../../input/text/text.component'
], ],
}) })
export class TagEditDialogComponent extends EditDialogComponent<Tag> { export class TagEditDialogComponent extends EditDialogComponent<Tag> {
constructor( constructor() {
service: TagService, super()
activeModal: NgbActiveModal, this.service = inject(TagService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService this.settingsService = inject(SettingsService)
) {
super(service, activeModal, userService, settingsService)
} }
getCreateTitle() { getCreateTitle() {

View File

@@ -1,11 +1,10 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { first } from 'rxjs' import { first } from 'rxjs'
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'
import { Group } from 'src/app/data/group' import { Group } from 'src/app/data/group'
@@ -37,21 +36,21 @@ export class UserEditDialogComponent
extends EditDialogComponent<User> extends EditDialogComponent<User>
implements OnInit implements OnInit
{ {
private toastService = inject(ToastService)
private permissionsService = inject(PermissionsService)
private groupsService: GroupService
groups: Group[] groups: Group[]
passwordIsSet: boolean = false passwordIsSet: boolean = false
public totpLoading: boolean = false public totpLoading: boolean = false
constructor( constructor() {
service: UserService, super()
activeModal: NgbActiveModal, this.service = inject(UserService)
groupsService: GroupService, this.groupsService = inject(GroupService)
settingsService: SettingsService, this.settingsService = inject(SettingsService)
private toastService: ToastService,
private permissionsService: PermissionsService
) {
super(service, activeModal, service, settingsService)
groupsService this.groupsService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.groups = result.results)) .subscribe((result) => (this.groups = result.results))

View File

@@ -4,7 +4,7 @@ import {
moveItemInArray, moveItemInArray,
} from '@angular/cdk/drag-drop' } from '@angular/cdk/drag-drop'
import { NgTemplateOutlet } from '@angular/common' import { NgTemplateOutlet } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { import {
FormArray, FormArray,
FormControl, FormControl,
@@ -12,7 +12,7 @@ import {
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms' } from '@angular/forms'
import { NgbAccordionModule, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { first } from 'rxjs' import { first } from 'rxjs'
import { Correspondent } from 'src/app/data/correspondent' import { Correspondent } from 'src/app/data/correspondent'
@@ -171,6 +171,12 @@ export class WorkflowEditDialogComponent
public WorkflowTriggerType = WorkflowTriggerType public WorkflowTriggerType = WorkflowTriggerType
public WorkflowActionType = WorkflowActionType public WorkflowActionType = WorkflowActionType
private correspondentService: CorrespondentService
private documentTypeService: DocumentTypeService
private storagePathService: StoragePathService
private mailRuleService: MailRuleService
private customFieldsService: CustomFieldsService
templates: Workflow[] templates: Workflow[]
correspondents: Correspondent[] correspondents: Correspondent[]
documentTypes: DocumentType[] documentTypes: DocumentType[]
@@ -183,40 +189,38 @@ export class WorkflowEditDialogComponent
private allowedActionTypes = [] private allowedActionTypes = []
constructor( constructor() {
service: WorkflowService, super()
activeModal: NgbActiveModal, this.service = inject(WorkflowService)
correspondentService: CorrespondentService, this.correspondentService = inject(CorrespondentService)
documentTypeService: DocumentTypeService, this.documentTypeService = inject(DocumentTypeService)
storagePathService: StoragePathService, this.storagePathService = inject(StoragePathService)
mailRuleService: MailRuleService, this.mailRuleService = inject(MailRuleService)
userService: UserService, this.userService = inject(UserService)
settingsService: SettingsService, this.settingsService = inject(SettingsService)
customFieldsService: CustomFieldsService this.customFieldsService = inject(CustomFieldsService)
) {
super(service, activeModal, userService, settingsService)
correspondentService this.correspondentService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.correspondents = result.results)) .subscribe((result) => (this.correspondents = result.results))
documentTypeService this.documentTypeService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.documentTypes = result.results)) .subscribe((result) => (this.documentTypes = result.results))
storagePathService this.storagePathService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.storagePaths = result.results)) .subscribe((result) => (this.storagePaths = result.results))
mailRuleService this.mailRuleService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => (this.mailRules = result.results)) .subscribe((result) => (this.mailRules = result.results))
customFieldsService this.customFieldsService
.listAll() .listAll()
.pipe(first()) .pipe(first())
.subscribe((result) => { .subscribe((result) => {

View File

@@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core' import { Component, Input, inject } from '@angular/core'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -13,6 +13,10 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
imports: [FormsModule, NgxBootstrapIconsModule], imports: [FormsModule, NgxBootstrapIconsModule],
}) })
export class EmailDocumentDialogComponent extends LoadingComponentWithPermissions { export class EmailDocumentDialogComponent extends LoadingComponentWithPermissions {
private activeModal = inject(NgbActiveModal)
private documentService = inject(DocumentService)
private toastService = inject(ToastService)
@Input() @Input()
title = $localize`Email Document` title = $localize`Email Document`
@@ -37,11 +41,7 @@ export class EmailDocumentDialogComponent extends LoadingComponentWithPermission
public emailSubject: string = '' public emailSubject: string = ''
public emailMessage: string = '' public emailMessage: string = ''
constructor( constructor() {
private activeModal: NgbActiveModal,
private documentService: DocumentService,
private toastService: ToastService
) {
super() super()
this.loading = false this.loading = false
} }

View File

@@ -7,6 +7,7 @@ import {
OnInit, OnInit,
Output, Output,
ViewChild, ViewChild,
inject,
} from '@angular/core' } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbDropdown, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap' import { NgbDropdown, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
@@ -434,6 +435,9 @@ export class FilterableDropdownComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit implements OnInit
{ {
private filterPipe = inject(FilterPipe)
private hotkeyService = inject(HotKeyService)
@ViewChild('listFilterTextInput') listFilterTextInput: ElementRef @ViewChild('listFilterTextInput') listFilterTextInput: ElementRef
@ViewChild('dropdown') dropdown: NgbDropdown @ViewChild('dropdown') dropdown: NgbDropdown
@ViewChild('buttonItems') buttonItems: ElementRef @ViewChild('buttonItems') buttonItems: ElementRef
@@ -536,10 +540,7 @@ export class FilterableDropdownComponent
private keyboardIndex: number private keyboardIndex: number
constructor( constructor() {
private filterPipe: FilterPipe,
private hotkeyService: HotKeyService
) {
super() super()
this.selectionModelChange.subscribe((updatedModel) => { this.selectionModelChange.subscribe((updatedModel) => {
this.modelIsDirty = updatedModel.isDirty() this.modelIsDirty = updatedModel.isDirty()

View File

@@ -1,4 +1,4 @@
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
const SYMBOLS = { const SYMBOLS = {
@@ -19,11 +19,11 @@ const SYMBOLS = {
styleUrl: './hotkey-dialog.component.scss', styleUrl: './hotkey-dialog.component.scss',
}) })
export class HotkeyDialogComponent { export class HotkeyDialogComponent {
activeModal = inject(NgbActiveModal)
public title: string = $localize`Keyboard shortcuts` public title: string = $localize`Keyboard shortcuts`
public hotkeys: Map<string, string> = new Map() public hotkeys: Map<string, string> = new Map()
constructor(public activeModal: NgbActiveModal) {}
public close(): void { public close(): void {
this.activeModal.close() this.activeModal.close()
} }

View File

@@ -2,6 +2,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
forwardRef, forwardRef,
inject,
Input, Input,
Output, Output,
} from '@angular/core' } from '@angular/core'
@@ -55,7 +56,9 @@ import { UrlComponent } from '../url/url.component'
export class CustomFieldsValuesComponent extends AbstractInputComponent<Object> { export class CustomFieldsValuesComponent extends AbstractInputComponent<Object> {
public CustomFieldDataType = CustomFieldDataType public CustomFieldDataType = CustomFieldDataType
constructor(customFieldsService: CustomFieldsService) { constructor() {
const customFieldsService = inject(CustomFieldsService)
super() super()
customFieldsService.listAll().subscribe((items) => { customFieldsService.listAll().subscribe((items) => {
this.fields = items.results this.fields = items.results

View File

@@ -2,6 +2,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
forwardRef, forwardRef,
inject,
Input, Input,
OnInit, OnInit,
Output, Output,
@@ -45,13 +46,9 @@ export class DateComponent
extends AbstractInputComponent<string> extends AbstractInputComponent<string>
implements OnInit implements OnInit
{ {
constructor( private settings = inject(SettingsService)
private settings: SettingsService, private ngbDateParserFormatter = inject(NgbDateParserFormatter)
private ngbDateParserFormatter: NgbDateParserFormatter, private isoDateAdapter = inject<NgbDateAdapter<string>>(NgbDateAdapter)
private isoDateAdapter: NgbDateAdapter<string>
) {
super()
}
@Input() @Input()
suggestions: string[] suggestions: string[]

View File

@@ -1,5 +1,12 @@
import { AsyncPipe, NgTemplateOutlet } from '@angular/common' import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core' import {
Component,
forwardRef,
inject,
Input,
OnDestroy,
OnInit,
} from '@angular/core'
import { import {
FormsModule, FormsModule,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
@@ -52,6 +59,8 @@ export class DocumentLinkComponent
extends AbstractInputComponent<any[]> extends AbstractInputComponent<any[]>
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
private documentsService = inject(DocumentService)
documentsInput$ = new Subject<string>() documentsInput$ = new Subject<string>()
foundDocuments$: Observable<Document[]> foundDocuments$: Observable<Document[]>
loading = false loading = false
@@ -75,10 +84,6 @@ export class DocumentLinkComponent
return this.selectedDocuments.map((d) => d.id) return this.selectedDocuments.map((d) => d.id)
} }
constructor(private documentsService: DocumentService) {
super()
}
ngOnInit() { ngOnInit() {
this.loadDocs() this.loadDocs()
} }

View File

@@ -1,5 +1,6 @@
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http' import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
import { provideHttpClientTesting } from '@angular/common/http/testing' import { provideHttpClientTesting } from '@angular/common/http/testing'
import { LOCALE_ID } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing' import { ComponentFixture, TestBed } from '@angular/core/testing'
import { NG_VALUE_ACCESSOR } from '@angular/forms' import { NG_VALUE_ACCESSOR } from '@angular/forms'
import { MonetaryComponent } from './monetary.component' import { MonetaryComponent } from './monetary.component'
@@ -41,8 +42,6 @@ describe('MonetaryComponent', () => {
it('should set the default currency code based on LOCALE_ID', () => { it('should set the default currency code based on LOCALE_ID', () => {
expect(component.defaultCurrencyCode).toEqual('USD') // default expect(component.defaultCurrencyCode).toEqual('USD') // default
component = new MonetaryComponent('pt-BR')
expect(component.defaultCurrencyCode).toEqual('BRL')
}) })
it('should support setting a default currency code', () => { it('should support setting a default currency code', () => {
@@ -87,3 +86,28 @@ describe('MonetaryComponent', () => {
expect(component.value).toEqual('USD0.00') expect(component.value).toEqual('USD0.00')
}) })
}) })
describe('MonetaryComponent (Alternate Locale)', () => {
let component: MonetaryComponent
let fixture: ComponentFixture<MonetaryComponent>
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MonetaryComponent],
providers: [
{ provide: LOCALE_ID, useValue: 'pt-BR' }, // Brazilian Portuguese
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting(),
],
}).compileComponents()
fixture = TestBed.createComponent(MonetaryComponent)
fixture.debugElement.injector.get(NG_VALUE_ACCESSOR)
component = fixture.componentInstance
fixture.detectChanges()
})
it('should set the default currency code based on LOCALE_ID', () => {
expect(component.defaultCurrencyCode).toEqual('BRL')
})
})

View File

@@ -1,5 +1,5 @@
import { CurrencyPipe, getLocaleCurrencyCode } from '@angular/common' import { CurrencyPipe, getLocaleCurrencyCode } from '@angular/common'
import { Component, forwardRef, Inject, Input, LOCALE_ID } from '@angular/core' import { Component, forwardRef, inject, Input, LOCALE_ID } from '@angular/core'
import { import {
FormsModule, FormsModule,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
@@ -27,6 +27,8 @@ import { AbstractInputComponent } from '../abstract-input'
], ],
}) })
export class MonetaryComponent extends AbstractInputComponent<string> { export class MonetaryComponent extends AbstractInputComponent<string> {
currentLocale = inject(LOCALE_ID)
public currency: string = '' public currency: string = ''
public _monetaryValue: string = '' public _monetaryValue: string = ''
@@ -45,11 +47,10 @@ export class MonetaryComponent extends AbstractInputComponent<string> {
if (currency) this.defaultCurrencyCode = currency if (currency) this.defaultCurrencyCode = currency
} }
constructor(@Inject(LOCALE_ID) currentLocale: string) { constructor() {
super() super()
this.currency = this.defaultCurrencyCode = this.currency = this.defaultCurrencyCode =
this.defaultCurrency ?? getLocaleCurrencyCode(currentLocale) this.defaultCurrency ?? getLocaleCurrencyCode(this.currentLocale)
} }
writeValue(newValue: any): void { writeValue(newValue: any): void {

View File

@@ -1,4 +1,4 @@
import { Component, forwardRef, Input } from '@angular/core' import { Component, forwardRef, inject, Input } from '@angular/core'
import { import {
FormsModule, FormsModule,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
@@ -22,16 +22,14 @@ import { AbstractInputComponent } from '../abstract-input'
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule], imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
}) })
export class NumberComponent extends AbstractInputComponent<number> { export class NumberComponent extends AbstractInputComponent<number> {
private documentService = inject(DocumentService)
@Input() @Input()
showAdd: boolean = true showAdd: boolean = true
@Input() @Input()
step: number = 1 step: number = 1
constructor(private documentService: DocumentService) {
super()
}
nextAsn() { nextAsn() {
if (this.value) { if (this.value) {
return return

View File

@@ -1,4 +1,4 @@
import { Component, forwardRef } from '@angular/core' import { Component, forwardRef, inject } from '@angular/core'
import { import {
FormsModule, FormsModule,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
@@ -26,7 +26,9 @@ import { AbstractInputComponent } from '../../abstract-input'
export class PermissionsGroupComponent extends AbstractInputComponent<Group> { export class PermissionsGroupComponent extends AbstractInputComponent<Group> {
groups: Group[] groups: Group[]
constructor(groupService: GroupService) { constructor() {
const groupService = inject(GroupService)
super() super()
groupService groupService
.listAll() .listAll()

View File

@@ -1,4 +1,4 @@
import { Component, forwardRef } from '@angular/core' import { Component, forwardRef, inject } from '@angular/core'
import { import {
FormsModule, FormsModule,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
@@ -8,7 +8,6 @@ import { NgSelectComponent } from '@ng-select/ng-select'
import { first } from 'rxjs/operators' import { first } from 'rxjs/operators'
import { User } from 'src/app/data/user' import { User } from 'src/app/data/user'
import { UserService } from 'src/app/services/rest/user.service' import { UserService } from 'src/app/services/rest/user.service'
import { SettingsService } from 'src/app/services/settings.service'
import { AbstractInputComponent } from '../../abstract-input' import { AbstractInputComponent } from '../../abstract-input'
@Component({ @Component({
@@ -27,7 +26,9 @@ import { AbstractInputComponent } from '../../abstract-input'
export class PermissionsUserComponent extends AbstractInputComponent<User[]> { export class PermissionsUserComponent extends AbstractInputComponent<User[]> {
users: User[] users: User[]
constructor(userService: UserService, settings: SettingsService) { constructor() {
const userService = inject(UserService)
super() super()
userService userService
.listAll() .listAll()

View File

@@ -2,6 +2,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
forwardRef, forwardRef,
inject,
Input, Input,
OnInit, OnInit,
Output, Output,
@@ -45,10 +46,10 @@ import { TagComponent } from '../../tag/tag.component'
], ],
}) })
export class TagsComponent implements OnInit, ControlValueAccessor { export class TagsComponent implements OnInit, ControlValueAccessor {
constructor( private tagService = inject(TagService)
private tagService: TagService, private modalService = inject(NgbModal)
private modalService: NgbModal
) { constructor() {
this.createTagRef = this.createTag.bind(this) this.createTagRef = this.createTag.bind(this)
} }

View File

@@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core' import { Component, Input, inject } from '@angular/core'
import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
import { SettingsService } from 'src/app/services/settings.service' import { SettingsService } from 'src/app/services/settings.service'
import { environment } from 'src/environments/environment' import { environment } from 'src/environments/environment'
@@ -9,6 +9,8 @@ import { environment } from 'src/environments/environment'
styleUrls: ['./logo.component.scss'], styleUrls: ['./logo.component.scss'],
}) })
export class LogoComponent { export class LogoComponent {
private settingsService = inject(SettingsService)
@Input() @Input()
extra_classes: string extra_classes: string
@@ -24,8 +26,6 @@ export class LogoComponent {
: null : null
} }
constructor(private settingsService: SettingsService) {}
getClasses() { getClasses() {
return ['logo'].concat(this.extra_classes).join(' ') return ['logo'].concat(this.extra_classes).join(' ')
} }

View File

@@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core' import { Component, Input, inject } from '@angular/core'
import { Title } from '@angular/platform-browser' import { Title } from '@angular/platform-browser'
import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap' import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -12,7 +12,7 @@ import { environment } from 'src/environments/environment'
imports: [NgbPopoverModule, NgxBootstrapIconsModule, TourNgBootstrapModule], imports: [NgbPopoverModule, NgxBootstrapIconsModule, TourNgBootstrapModule],
}) })
export class PageHeaderComponent { export class PageHeaderComponent {
constructor(private titleService: Title) {} private titleService = inject(Title)
_title = '' _title = ''

View File

@@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, Output } from '@angular/core' import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
@@ -24,13 +24,13 @@ import { SwitchComponent } from '../input/switch/switch.component'
], ],
}) })
export class PermissionsDialogComponent { export class PermissionsDialogComponent {
activeModal = inject(NgbActiveModal)
private userService = inject(UserService)
users: User[] users: User[]
private o: ObjectWithPermissions = undefined private o: ObjectWithPermissions = undefined
constructor( constructor() {
public activeModal: NgbActiveModal,
private userService: UserService
) {
this.userService.listAll().subscribe((r) => (this.users = r.results)) this.userService.listAll().subscribe((r) => (this.users = r.results))
} }

View File

@@ -1,5 +1,5 @@
import { NgClass } from '@angular/common' import { NgClass } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core' import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap' import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'
import { NgSelectComponent } from '@ng-select/ng-select' import { NgSelectComponent } from '@ng-select/ng-select'
@@ -58,6 +58,9 @@ export enum OwnerFilterType {
], ],
}) })
export class PermissionsFilterDropdownComponent extends ComponentWithPermissions { export class PermissionsFilterDropdownComponent extends ComponentWithPermissions {
permissionsService = inject(PermissionsService)
private settingsService = inject(SettingsService)
public OwnerFilterType = OwnerFilterType public OwnerFilterType = OwnerFilterType
@Input() @Input()
@@ -83,12 +86,12 @@ export class PermissionsFilterDropdownComponent extends ComponentWithPermissions
) )
} }
constructor( constructor() {
public permissionsService: PermissionsService, const userService = inject(UserService)
userService: UserService,
private settingsService: SettingsService
) {
super() super()
const permissionsService = this.permissionsService
if ( if (
permissionsService.currentUserCan( permissionsService.currentUserCan(
PermissionAction.View, PermissionAction.View,

View File

@@ -1,5 +1,5 @@
import { KeyValuePipe } from '@angular/common' import { KeyValuePipe } from '@angular/common'
import { Component, forwardRef, Input, OnInit } from '@angular/core' import { Component, forwardRef, inject, Input, OnInit } from '@angular/core'
import { import {
AbstractControl, AbstractControl,
ControlValueAccessor, ControlValueAccessor,
@@ -43,6 +43,9 @@ export class PermissionsSelectComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, ControlValueAccessor implements OnInit, ControlValueAccessor
{ {
private readonly permissionsService = inject(PermissionsService)
private readonly settingsService = inject(SettingsService)
@Input() @Input()
title: string = 'Permissions' title: string = 'Permissions'
@@ -76,10 +79,7 @@ export class PermissionsSelectComponent
public allowedTypes = Object.keys(PermissionType) public allowedTypes = Object.keys(PermissionType)
constructor( constructor() {
private readonly permissionsService: PermissionsService,
private readonly settingsService: SettingsService
) {
super() super()
if (!this.settingsService.get(SETTINGS_KEYS.AUDITLOG_ENABLED)) { if (!this.settingsService.get(SETTINGS_KEYS.AUDITLOG_ENABLED)) {
this.allowedTypes.splice(this.allowedTypes.indexOf('History'), 1) this.allowedTypes.splice(this.allowedTypes.indexOf('History'), 1)

View File

@@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http' import { HttpClient } from '@angular/common/http'
import { Component, Input, OnDestroy, ViewChild } from '@angular/core' import { Component, inject, Input, OnDestroy, ViewChild } from '@angular/core'
import { NgbPopover, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap' import { NgbPopover, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import { PdfViewerComponent, PdfViewerModule } from 'ng2-pdf-viewer' import { PdfViewerComponent, PdfViewerModule } from 'ng2-pdf-viewer'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -24,6 +24,10 @@ import { SettingsService } from 'src/app/services/settings.service'
], ],
}) })
export class PreviewPopupComponent implements OnDestroy { export class PreviewPopupComponent implements OnDestroy {
private settingsService = inject(SettingsService)
private documentService = inject(DocumentService)
private http = inject(HttpClient)
private _document: Document private _document: Document
@Input() @Input()
set document(document: Document) { set document(document: Document) {
@@ -82,12 +86,6 @@ export class PreviewPopupComponent implements OnDestroy {
) )
} }
constructor(
private settingsService: SettingsService,
private documentService: DocumentService,
private http: HttpClient
) {}
ngOnDestroy(): void { ngOnDestroy(): void {
this.unsubscribeNotifier.next(this) this.unsubscribeNotifier.next(this)
} }

View File

@@ -1,5 +1,5 @@
import { Clipboard } from '@angular/cdk/clipboard' import { Clipboard } from '@angular/cdk/clipboard'
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
@@ -46,6 +46,11 @@ export class ProfileEditDialogComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit implements OnInit
{ {
private profileService = inject(ProfileService)
activeModal = inject(NgbActiveModal)
private toastService = inject(ToastService)
private clipboard = inject(Clipboard)
public networkActive: boolean = false public networkActive: boolean = false
public error: any public error: any
@@ -83,15 +88,6 @@ export class ProfileEditDialogComponent
public socialAccounts: SocialAccount[] = [] public socialAccounts: SocialAccount[] = []
public socialAccountProviders: SocialAccountProvider[] = [] public socialAccountProviders: SocialAccountProvider[] = []
constructor(
private profileService: ProfileService,
public activeModal: NgbActiveModal,
private toastService: ToastService,
private clipboard: Clipboard
) {
super()
}
ngOnInit(): void { ngOnInit(): void {
this.networkActive = true this.networkActive = true
this.profileService this.profileService

View File

@@ -10,6 +10,7 @@ import {
fakeAsync, fakeAsync,
tick, tick,
} from '@angular/core/testing' } from '@angular/core/testing'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { By } from '@angular/platform-browser' import { By } from '@angular/platform-browser'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
@@ -33,6 +34,8 @@ describe('ShareLinksDialogComponent', () => {
imports: [ imports: [
ShareLinksDialogComponent, ShareLinksDialogComponent,
NgxBootstrapIconsModule.pick(allIcons), NgxBootstrapIconsModule.pick(allIcons),
FormsModule,
ReactiveFormsModule,
], ],
providers: [ providers: [
provideHttpClient(withInterceptorsFromDi()), provideHttpClient(withInterceptorsFromDi()),
@@ -223,16 +226,18 @@ describe('ShareLinksDialogComponent', () => {
) )
}) })
it('should disable archive switch & option if no archive available', () => { it('should disable archive switch & option if no archive available', (done) => {
component.hasArchiveVersion = false component.hasArchiveVersion = false
component.ngOnInit() component.ngOnInit()
fixture.detectChanges() fixture.detectChanges()
expect(component.useArchiveVersion).toBeFalsy() expect(component.useArchiveVersion).toBeFalsy()
expect( setTimeout(() => {
fixture.debugElement.query(By.css("input[type='checkbox']")).attributes[ // some stupid change detection issue
'ng-reflect-is-disabled' const inputEl = fixture.debugElement.query(By.css('#versionSwitch'))
] .nativeElement as HTMLInputElement
).toBeTruthy() expect(inputEl.disabled).toBeTruthy()
done()
})
}) })
it('should support close', () => { it('should support close', () => {

View File

@@ -1,5 +1,5 @@
import { Clipboard } from '@angular/cdk/clipboard' import { Clipboard } from '@angular/cdk/clipboard'
import { Component, Input, OnInit } from '@angular/core' import { Component, Input, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -16,6 +16,11 @@ import { environment } from 'src/environments/environment'
imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule], imports: [FormsModule, ReactiveFormsModule, NgxBootstrapIconsModule],
}) })
export class ShareLinksDialogComponent implements OnInit { export class ShareLinksDialogComponent implements OnInit {
private activeModal = inject(NgbActiveModal)
private shareLinkService = inject(ShareLinkService)
private toastService = inject(ToastService)
private clipboard = inject(Clipboard)
EXPIRATION_OPTIONS = [ EXPIRATION_OPTIONS = [
{ label: $localize`1 day`, value: 1 }, { label: $localize`1 day`, value: 1 },
{ label: $localize`7 days`, value: 7 }, { label: $localize`7 days`, value: 7 },
@@ -58,13 +63,6 @@ export class ShareLinksDialogComponent implements OnInit {
useArchiveVersion: boolean = true useArchiveVersion: boolean = true
constructor(
private activeModal: NgbActiveModal,
private shareLinkService: ShareLinkService,
private toastService: ToastService,
private clipboard: Clipboard
) {}
ngOnInit(): void { ngOnInit(): void {
if (this._documentId !== undefined) this.refresh() if (this._documentId !== undefined) this.refresh()
} }

View File

@@ -1,5 +1,5 @@
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard' import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { import {
NgbActiveModal, NgbActiveModal,
NgbModalModule, NgbModalModule,
@@ -35,6 +35,13 @@ import { environment } from 'src/environments/environment'
], ],
}) })
export class SystemStatusDialogComponent implements OnInit { export class SystemStatusDialogComponent implements OnInit {
activeModal = inject(NgbActiveModal)
private clipboard = inject(Clipboard)
private systemStatusService = inject(SystemStatusService)
private tasksService = inject(TasksService)
private toastService = inject(ToastService)
private permissionsService = inject(PermissionsService)
public SystemStatusItemStatus = SystemStatusItemStatus public SystemStatusItemStatus = SystemStatusItemStatus
public PaperlessTaskName = PaperlessTaskName public PaperlessTaskName = PaperlessTaskName
public status: SystemStatus public status: SystemStatus
@@ -49,15 +56,6 @@ export class SystemStatusDialogComponent implements OnInit {
return this.permissionsService.isSuperUser() return this.permissionsService.isSuperUser()
} }
constructor(
public activeModal: NgbActiveModal,
private clipboard: Clipboard,
private systemStatusService: SystemStatusService,
private tasksService: TasksService,
private toastService: ToastService,
private permissionsService: PermissionsService
) {}
public ngOnInit() { public ngOnInit() {
this.versionMismatch = this.versionMismatch =
environment.production && environment.production &&

View File

@@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core' import { Component, inject, Input } from '@angular/core'
import { Tag } from 'src/app/data/tag' import { Tag } from 'src/app/data/tag'
import { import {
PermissionAction, PermissionAction,
@@ -13,14 +13,12 @@ import { TagService } from 'src/app/services/rest/tag.service'
styleUrls: ['./tag.component.scss'], styleUrls: ['./tag.component.scss'],
}) })
export class TagComponent { export class TagComponent {
private permissionsService = inject(PermissionsService)
private tagService = inject(TagService)
private _tag: Tag private _tag: Tag
private _tagID: number private _tagID: number
constructor(
private permissionsService: PermissionsService,
private tagService: TagService
) {}
@Input() @Input()
public set tag(tag: Tag) { public set tag(tag: Tag) {
this._tag = tag this._tag = tag

View File

@@ -1,6 +1,6 @@
import { Clipboard } from '@angular/cdk/clipboard' import { Clipboard } from '@angular/cdk/clipboard'
import { DecimalPipe } from '@angular/common' import { DecimalPipe } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core' import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { import {
NgbProgressbarModule, NgbProgressbarModule,
NgbToastModule, NgbToastModule,
@@ -21,6 +21,8 @@ import { Toast } from 'src/app/services/toast.service'
styleUrl: './toast.component.scss', styleUrl: './toast.component.scss',
}) })
export class ToastComponent { export class ToastComponent {
private clipboard = inject(Clipboard)
@Input() toast: Toast @Input() toast: Toast
@Input() autohide: boolean = true @Input() autohide: boolean = true
@@ -31,8 +33,6 @@ export class ToastComponent {
public copied: boolean = false public copied: boolean = false
constructor(private clipboard: Clipboard) {}
onShown(toast: Toast) { onShown(toast: Toast) {
if (!this.autohide) return if (!this.autohide) return

View File

@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { import {
NgbAccordionModule, NgbAccordionModule,
NgbProgressbarModule, NgbProgressbarModule,
@@ -20,7 +20,7 @@ import { ToastComponent } from '../toast/toast.component'
], ],
}) })
export class ToastsComponent implements OnInit, OnDestroy { export class ToastsComponent implements OnInit, OnDestroy {
constructor(public toastService: ToastService) {} toastService = inject(ToastService)
private subscription: Subscription private subscription: Subscription

View File

@@ -5,7 +5,7 @@ import {
DragDropModule, DragDropModule,
moveItemInArray, moveItemInArray,
} from '@angular/cdk/drag-drop' } from '@angular/cdk/drag-drop'
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { RouterModule } from '@angular/router' import { RouterModule } from '@angular/router'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap' import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap'
@@ -42,13 +42,13 @@ import { WelcomeWidgetComponent } from './widgets/welcome-widget/welcome-widget.
], ],
}) })
export class DashboardComponent extends ComponentWithPermissions { export class DashboardComponent extends ComponentWithPermissions {
settingsService = inject(SettingsService)
savedViewService = inject(SavedViewService)
private tourService = inject(TourService)
private toastService = inject(ToastService)
public dashboardViews: SavedView[] = [] public dashboardViews: SavedView[] = []
constructor( constructor() {
public settingsService: SettingsService,
public savedViewService: SavedViewService,
private tourService: TourService,
private toastService: ToastService
) {
super() super()
this.savedViewService.listAll().subscribe(() => { this.savedViewService.listAll().subscribe(() => {

View File

@@ -1,6 +1,7 @@
import { AsyncPipe, NgClass, NgStyle } from '@angular/common' import { AsyncPipe, NgClass, NgStyle } from '@angular/common'
import { import {
Component, Component,
inject,
Input, Input,
OnDestroy, OnDestroy,
OnInit, OnInit,
@@ -84,26 +85,22 @@ export class SavedViewWidgetComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
private documentService = inject(DocumentService)
private router = inject(Router)
private list = inject(DocumentListViewService)
private websocketStatusService = inject(WebsocketStatusService)
openDocumentsService = inject(OpenDocumentsService)
documentListViewService = inject(DocumentListViewService)
permissionsService = inject(PermissionsService)
private settingsService = inject(SettingsService)
private customFieldService = inject(CustomFieldsService)
public DisplayMode = DisplayMode public DisplayMode = DisplayMode
public DisplayField = DisplayField public DisplayField = DisplayField
public CustomFieldDataType = CustomFieldDataType public CustomFieldDataType = CustomFieldDataType
private customFields: CustomField[] = [] private customFields: CustomField[] = []
constructor(
private documentService: DocumentService,
private router: Router,
private list: DocumentListViewService,
private websocketStatusService: WebsocketStatusService,
public openDocumentsService: OpenDocumentsService,
public documentListViewService: DocumentListViewService,
public permissionsService: PermissionsService,
private settingsService: SettingsService,
private customFieldService: CustomFieldsService
) {
super()
}
@Input() @Input()
savedView: SavedView savedView: SavedView

View File

@@ -1,6 +1,6 @@
import { DecimalPipe } from '@angular/common' import { DecimalPipe } from '@angular/common'
import { HttpClient } from '@angular/common/http' import { HttpClient } from '@angular/common/http'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, inject, OnDestroy, OnInit } from '@angular/core'
import { RouterModule } from '@angular/router' import { RouterModule } from '@angular/router'
import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap' import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'
import * as mimeTypeNames from 'mime-names' import * as mimeTypeNames from 'mime-names'
@@ -51,15 +51,11 @@ export class StatisticsWidgetComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
loading: boolean = false private http = inject(HttpClient)
private websocketConnectionService = inject(WebsocketStatusService)
private documentListViewService = inject(DocumentListViewService)
constructor( loading: boolean = false
private http: HttpClient,
private websocketConnectionService: WebsocketStatusService,
private documentListViewService: DocumentListViewService
) {
super()
}
statistics: Statistics = {} statistics: Statistics = {}

View File

@@ -1,5 +1,5 @@
import { NgClass, NgTemplateOutlet } from '@angular/common' import { NgClass, NgTemplateOutlet } from '@angular/common'
import { Component, QueryList, ViewChildren } from '@angular/core' import { Component, QueryList, ViewChildren, inject } from '@angular/core'
import { RouterModule } from '@angular/router' import { RouterModule } from '@angular/router'
import { import {
NgbAlert, NgbAlert,
@@ -37,15 +37,11 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component'
], ],
}) })
export class UploadFileWidgetComponent extends ComponentWithPermissions { export class UploadFileWidgetComponent extends ComponentWithPermissions {
@ViewChildren(NgbAlert) alerts: QueryList<NgbAlert> private websocketStatusService = inject(WebsocketStatusService)
private uploadDocumentsService = inject(UploadDocumentsService)
settingsService = inject(SettingsService)
constructor( @ViewChildren(NgbAlert) alerts: QueryList<NgbAlert>
private websocketStatusService: WebsocketStatusService,
private uploadDocumentsService: UploadDocumentsService,
public settingsService: SettingsService
) {
super()
}
getStatus() { getStatus() {
return this.websocketStatusService.getConsumerStatus() return this.websocketStatusService.getConsumerStatus()

View File

@@ -1,4 +1,4 @@
import { Component, EventEmitter, Output } from '@angular/core' import { Component, EventEmitter, Output, inject } from '@angular/core'
import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap' import { NgbAlertModule } from '@ng-bootstrap/ng-bootstrap'
import { TourService } from 'ngx-ui-tour-ng-bootstrap' import { TourService } from 'ngx-ui-tour-ng-bootstrap'
@@ -9,7 +9,7 @@ import { TourService } from 'ngx-ui-tour-ng-bootstrap'
imports: [NgbAlertModule], imports: [NgbAlertModule],
}) })
export class WelcomeWidgetComponent { export class WelcomeWidgetComponent {
constructor(public readonly tourService: TourService) {} readonly tourService = inject(TourService)
@Output() @Output()
dismiss: EventEmitter<boolean> = new EventEmitter() dismiss: EventEmitter<boolean> = new EventEmitter()

View File

@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { FILTER_ASN } from '../../data/filter-rule-type' import { FILTER_ASN } from '../../data/filter-rule-type'
import { DocumentService } from '../../services/rest/document.service' import { DocumentService } from '../../services/rest/document.service'
@@ -9,12 +9,11 @@ import { DocumentService } from '../../services/rest/document.service'
styleUrls: ['./document-asn.component.scss'], styleUrls: ['./document-asn.component.scss'],
}) })
export class DocumentAsnComponent implements OnInit { export class DocumentAsnComponent implements OnInit {
private documentsService = inject(DocumentService)
private route = inject(ActivatedRoute)
private router = inject(Router)
asn: string asn: string
constructor(
private documentsService: DocumentService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit(): void { ngOnInit(): void {
this.route.paramMap.subscribe((paramMap) => { this.route.paramMap.subscribe((paramMap) => {

View File

@@ -1,6 +1,6 @@
import { AsyncPipe, NgTemplateOutlet } from '@angular/common' import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
import { HttpClient, HttpResponse } from '@angular/common/http' import { HttpClient, HttpResponse } from '@angular/common/http'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core' import { Component, inject, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { import {
FormArray, FormArray,
FormControl, FormControl,
@@ -176,6 +176,26 @@ export class DocumentDetailComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, OnDestroy, DirtyComponent implements OnInit, OnDestroy, DirtyComponent
{ {
private documentsService = inject(DocumentService)
private route = inject(ActivatedRoute)
private correspondentService = inject(CorrespondentService)
private documentTypeService = inject(DocumentTypeService)
private router = inject(Router)
private modalService = inject(NgbModal)
private openDocumentService = inject(OpenDocumentsService)
private documentListViewService = inject(DocumentListViewService)
private documentTitlePipe = inject(DocumentTitlePipe)
private toastService = inject(ToastService)
private settings = inject(SettingsService)
private storagePathService = inject(StoragePathService)
private permissionsService = inject(PermissionsService)
private userService = inject(UserService)
private customFieldsService = inject(CustomFieldsService)
private http = inject(HttpClient)
private hotKeyService = inject(HotKeyService)
private componentRouterService = inject(ComponentRouterService)
private deviceDetectorService = inject(DeviceDetectorService)
@ViewChild('inputTitle') @ViewChild('inputTitle')
titleInput: TextComponent titleInput: TextComponent
@@ -259,30 +279,6 @@ export class DocumentDetailComponent
DocumentDetailNavIDs = DocumentDetailNavIDs DocumentDetailNavIDs = DocumentDetailNavIDs
activeNavID: number activeNavID: number
constructor(
private documentsService: DocumentService,
private route: ActivatedRoute,
private correspondentService: CorrespondentService,
private documentTypeService: DocumentTypeService,
private router: Router,
private modalService: NgbModal,
private openDocumentService: OpenDocumentsService,
private documentListViewService: DocumentListViewService,
private documentTitlePipe: DocumentTitlePipe,
private toastService: ToastService,
private settings: SettingsService,
private storagePathService: StoragePathService,
private permissionsService: PermissionsService,
private userService: UserService,
private customFieldsService: CustomFieldsService,
private http: HttpClient,
private hotKeyService: HotKeyService,
private componentRouterService: ComponentRouterService,
private deviceDetectorService: DeviceDetectorService
) {
super()
}
titleKeyUp(event) { titleKeyUp(event) {
this.titleSubject.next(event.target?.value) this.titleSubject.next(event.target?.value)
} }

View File

@@ -1,5 +1,5 @@
import { AsyncPipe, KeyValuePipe, TitleCasePipe } from '@angular/common' import { AsyncPipe, KeyValuePipe, TitleCasePipe } from '@angular/common'
import { Component, Input, OnInit } from '@angular/core' import { Component, Input, OnInit, inject } from '@angular/core'
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap' import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { Observable, first, map, of } from 'rxjs' import { Observable, first, map, of } from 'rxjs'
@@ -26,6 +26,12 @@ import { UserService } from 'src/app/services/rest/user.service'
], ],
}) })
export class DocumentHistoryComponent implements OnInit { export class DocumentHistoryComponent implements OnInit {
private documentService = inject(DocumentService)
private correspondentService = inject(CorrespondentService)
private storagePathService = inject(StoragePathService)
private documentTypeService = inject(DocumentTypeService)
private userService = inject(UserService)
public AuditLogAction = AuditLogAction public AuditLogAction = AuditLogAction
private _documentId: number private _documentId: number
@@ -38,14 +44,6 @@ export class DocumentHistoryComponent implements OnInit {
public loading: boolean = true public loading: boolean = true
public entries: AuditLogEntry[] = [] public entries: AuditLogEntry[] = []
constructor(
private documentService: DocumentService,
private correspondentService: CorrespondentService,
private storagePathService: StoragePathService,
private documentTypeService: DocumentTypeService,
private userService: UserService
) {}
ngOnInit(): void { ngOnInit(): void {
if (this._documentId) { if (this._documentId) {
this.loading = true this.loading = true

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core' import { Component, inject, Input, OnDestroy, OnInit } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
@@ -71,6 +71,19 @@ export class BulkEditorComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
private documentTypeService = inject(DocumentTypeService)
private tagService = inject(TagService)
private correspondentService = inject(CorrespondentService)
list = inject(DocumentListViewService)
private documentService = inject(DocumentService)
private modalService = inject(NgbModal)
private openDocumentService = inject(OpenDocumentsService)
private settings = inject(SettingsService)
private toastService = inject(ToastService)
private storagePathService = inject(StoragePathService)
private customFieldService = inject(CustomFieldsService)
private permissionService = inject(PermissionsService)
tagSelectionModel = new FilterableDropdownSelectionModel(true) tagSelectionModel = new FilterableDropdownSelectionModel(true)
correspondentSelectionModel = new FilterableDropdownSelectionModel() correspondentSelectionModel = new FilterableDropdownSelectionModel()
documentTypeSelectionModel = new FilterableDropdownSelectionModel() documentTypeSelectionModel = new FilterableDropdownSelectionModel()
@@ -94,23 +107,6 @@ export class BulkEditorComponent
@Input() @Input()
public disabled: boolean = false public disabled: boolean = false
constructor(
private documentTypeService: DocumentTypeService,
private tagService: TagService,
private correspondentService: CorrespondentService,
public list: DocumentListViewService,
private documentService: DocumentService,
private modalService: NgbModal,
private openDocumentService: OpenDocumentsService,
private settings: SettingsService,
private toastService: ToastService,
private storagePathService: StoragePathService,
private customFieldService: CustomFieldsService,
private permissionService: PermissionsService
) {
super()
}
applyOnClose: boolean = this.settings.get( applyOnClose: boolean = this.settings.get(
SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE
) )

View File

@@ -1,4 +1,4 @@
import { Component, EventEmitter, Output } from '@angular/core' import { Component, EventEmitter, Output, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
@@ -38,6 +38,9 @@ import { DocumentService } from 'src/app/services/rest/document.service'
], ],
}) })
export class CustomFieldsBulkEditDialogComponent { export class CustomFieldsBulkEditDialogComponent {
private activeModal = inject(NgbActiveModal)
private documentService = inject(DocumentService)
CustomFieldDataType = CustomFieldDataType CustomFieldDataType = CustomFieldDataType
@Output() @Output()
@@ -73,11 +76,6 @@ export class CustomFieldsBulkEditDialogComponent {
public documents: number[] = [] public documents: number[] = []
constructor(
private activeModal: NgbActiveModal,
private documentService: DocumentService
) {}
initForm() { initForm() {
Object.keys(this.form.controls).forEach((key) => { Object.keys(this.form.controls).forEach((key) => {
if (!this._fieldsToAddIds.includes(parseInt(key))) { if (!this._fieldsToAddIds.includes(parseInt(key))) {

View File

@@ -6,6 +6,7 @@ import {
Input, Input,
Output, Output,
ViewChild, ViewChild,
inject,
} from '@angular/core' } from '@angular/core'
import { RouterModule } from '@angular/router' import { RouterModule } from '@angular/router'
import { import {
@@ -62,14 +63,10 @@ export class DocumentCardLargeComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements AfterViewInit implements AfterViewInit
{ {
DisplayField = DisplayField private documentService = inject(DocumentService)
settingsService = inject(SettingsService)
constructor( DisplayField = DisplayField
private documentService: DocumentService,
public settingsService: SettingsService
) {
super()
}
@Input() @Input()
selected = false selected = false

View File

@@ -71,14 +71,14 @@
} }
@if (displayFields.includes(DisplayField.CREATED)) { @if (displayFields.includes(DisplayField.CREATED)) {
<div class="list-group-item bg-transparent p-0 border-0 d-flex flex-wrap-reverse justify-content-between"> <div class="list-group-item bg-transparent p-0 border-0 d-flex flex-wrap-reverse justify-content-between">
<ng-template #dateTooltip> <ng-template #dateCreatedTooltip>
<div class="d-flex flex-column text-light"> <div class="d-flex flex-column text-light">
<span i18n>Created: {{ document.created | customDate }}</span> <span i18n>Created: {{ document.created | customDate }}</span>
<span i18n>Added: {{ document.added | customDate }}</span> <span i18n>Added: {{ document.added | customDate }}</span>
<span i18n>Modified: {{ document.modified | customDate }}</span> <span i18n>Modified: {{ document.modified | customDate }}</span>
</div> </div>
</ng-template> </ng-template>
<div class="ps-0 p-1" placement="top" [ngbTooltip]="dateTooltip"> <div class="ps-0 p-1" placement="top" [ngbTooltip]="dateCreatedTooltip">
<i-bs width="1em" height="1em" class="me-2 text-muted" name="calendar-event"></i-bs> <i-bs width="1em" height="1em" class="me-2 text-muted" name="calendar-event"></i-bs>
<small>{{document.created | customDate:'mediumDate'}}</small> <small>{{document.created | customDate:'mediumDate'}}</small>
</div> </div>
@@ -86,14 +86,14 @@
} }
@if (displayFields.includes(DisplayField.ADDED)) { @if (displayFields.includes(DisplayField.ADDED)) {
<div class="list-group-item bg-transparent p-0 border-0 d-flex flex-wrap-reverse justify-content-between"> <div class="list-group-item bg-transparent p-0 border-0 d-flex flex-wrap-reverse justify-content-between">
<ng-template #dateTooltip> <ng-template #dateAddedTooltip>
<div class="d-flex flex-column text-light"> <div class="d-flex flex-column text-light">
<span i18n>Created: {{ document.created | customDate }}</span> <span i18n>Created: {{ document.created | customDate }}</span>
<span i18n>Added: {{ document.added | customDate }}</span> <span i18n>Added: {{ document.added | customDate }}</span>
<span i18n>Modified: {{ document.modified | customDate }}</span> <span i18n>Modified: {{ document.modified | customDate }}</span>
</div> </div>
</ng-template> </ng-template>
<div class="ps-0 p-1" placement="top" [ngbTooltip]="dateTooltip"> <div class="ps-0 p-1" placement="top" [ngbTooltip]="dateAddedTooltip">
<i-bs width="1em" height="1em" class="me-2 text-muted" name="calendar-event"></i-bs> <i-bs width="1em" height="1em" class="me-2 text-muted" name="calendar-event"></i-bs>
<small>{{document.added | customDate:'mediumDate'}}</small> <small>{{document.added | customDate:'mediumDate'}}</small>
</div> </div>

View File

@@ -6,6 +6,7 @@ import {
Input, Input,
Output, Output,
ViewChild, ViewChild,
inject,
} from '@angular/core' } from '@angular/core'
import { RouterModule } from '@angular/router' import { RouterModule } from '@angular/router'
import { import {
@@ -63,14 +64,10 @@ export class DocumentCardSmallComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements AfterViewInit implements AfterViewInit
{ {
DisplayField = DisplayField private documentService = inject(DocumentService)
settingsService = inject(SettingsService)
constructor( DisplayField = DisplayField
private documentService: DocumentService,
public settingsService: SettingsService
) {
super()
}
@Input() @Input()
selected = false selected = false

View File

@@ -1,6 +1,7 @@
import { AsyncPipe, NgClass, NgTemplateOutlet } from '@angular/common' import { AsyncPipe, NgClass, NgTemplateOutlet } from '@angular/common'
import { import {
Component, Component,
inject,
OnDestroy, OnDestroy,
OnInit, OnInit,
QueryList, QueryList,
@@ -103,25 +104,21 @@ export class DocumentListComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
list = inject(DocumentListViewService)
savedViewService = inject(SavedViewService)
route = inject(ActivatedRoute)
private router = inject(Router)
private toastService = inject(ToastService)
private modalService = inject(NgbModal)
private websocketStatusService = inject(WebsocketStatusService)
openDocumentsService = inject(OpenDocumentsService)
settingsService = inject(SettingsService)
private hotKeyService = inject(HotKeyService)
permissionService = inject(PermissionsService)
DisplayField = DisplayField DisplayField = DisplayField
DisplayMode = DisplayMode DisplayMode = DisplayMode
constructor(
public list: DocumentListViewService,
public savedViewService: SavedViewService,
public route: ActivatedRoute,
private router: Router,
private toastService: ToastService,
private modalService: NgbModal,
private websocketStatusService: WebsocketStatusService,
public openDocumentsService: OpenDocumentsService,
public settingsService: SettingsService,
private hotKeyService: HotKeyService,
public permissionService: PermissionsService
) {
super()
}
@ViewChild('filterEditor') @ViewChild('filterEditor')
private filterEditor: FilterEditorComponent private filterEditor: FilterEditorComponent

View File

@@ -8,6 +8,7 @@ import {
OnInit, OnInit,
Output, Output,
ViewChild, ViewChild,
inject,
} from '@angular/core' } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { import {
@@ -240,6 +241,15 @@ export class FilterEditorComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit, OnDestroy, AfterViewInit implements OnInit, OnDestroy, AfterViewInit
{ {
private documentTypeService = inject(DocumentTypeService)
private tagService = inject(TagService)
private correspondentService = inject(CorrespondentService)
private documentService = inject(DocumentService)
private storagePathService = inject(StoragePathService)
permissionsService = inject(PermissionsService)
private customFieldService = inject(CustomFieldsService)
private searchService = inject(SearchService)
generateFilterName() { generateFilterName() {
if (this.filterRules.length == 1) { if (this.filterRules.length == 1) {
let rule = this.filterRules[0] let rule = this.filterRules[0]
@@ -313,19 +323,6 @@ export class FilterEditorComponent
return '' return ''
} }
constructor(
private documentTypeService: DocumentTypeService,
private tagService: TagService,
private correspondentService: CorrespondentService,
private documentService: DocumentService,
private storagePathService: StoragePathService,
public permissionsService: PermissionsService,
private customFieldService: CustomFieldsService,
private searchService: SearchService
) {
super()
}
@ViewChild('textFilterInput') @ViewChild('textFilterInput')
textFilterInput: ElementRef textFilterInput: ElementRef
@@ -1219,6 +1216,7 @@ export class FilterEditorComponent
resetSelected() { resetSelected() {
this.textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT this.textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT
this.documentService.searchQuery = ''
this.filterRules = this._unmodifiedFilterRules this.filterRules = this._unmodifiedFilterRules
this.updateRules() this.updateRules()
} }

View File

@@ -1,4 +1,11 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import {
Component,
EventEmitter,
Input,
OnInit,
Output,
inject,
} from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
@@ -16,7 +23,7 @@ import { TextComponent } from '../../common/input/text/text.component'
imports: [CheckComponent, TextComponent, FormsModule, ReactiveFormsModule], imports: [CheckComponent, TextComponent, FormsModule, ReactiveFormsModule],
}) })
export class SaveViewConfigDialogComponent implements OnInit { export class SaveViewConfigDialogComponent implements OnInit {
constructor(private modal: NgbActiveModal) {} private modal = inject(NgbActiveModal)
@Output() @Output()
public saveClicked = new EventEmitter() public saveClicked = new EventEmitter()

View File

@@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, Output } from '@angular/core' import { Component, EventEmitter, Input, Output, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
@@ -28,6 +28,10 @@ import { ComponentWithPermissions } from '../with-permissions/with-permissions.c
], ],
}) })
export class DocumentNotesComponent extends ComponentWithPermissions { export class DocumentNotesComponent extends ComponentWithPermissions {
private notesService = inject(DocumentNotesService)
private toastService = inject(ToastService)
private usersService = inject(UserService)
noteForm: FormGroup = new FormGroup({ noteForm: FormGroup = new FormGroup({
newNote: new FormControl(''), newNote: new FormControl(''),
}) })
@@ -48,11 +52,7 @@ export class DocumentNotesComponent extends ComponentWithPermissions {
updated: EventEmitter<DocumentNote[]> = new EventEmitter() updated: EventEmitter<DocumentNote[]> = new EventEmitter()
users: User[] users: User[]
constructor( constructor() {
private notesService: DocumentNotesService,
private toastService: ToastService,
private usersService: UserService
) {
super() super()
this.usersService.listAll().subscribe({ this.usersService.listAll().subscribe({
next: (users) => { next: (users) => {

View File

@@ -1,4 +1,4 @@
import { Component, HostListener } from '@angular/core' import { Component, HostListener, inject } from '@angular/core'
import { import {
PermissionAction, PermissionAction,
PermissionsService, PermissionsService,
@@ -15,17 +15,15 @@ import { UploadDocumentsService } from 'src/app/services/upload-documents.servic
imports: [], imports: [],
}) })
export class FileDropComponent { export class FileDropComponent {
private settings = inject(SettingsService)
private toastService = inject(ToastService)
private uploadDocumentsService = inject(UploadDocumentsService)
private permissionsService = inject(PermissionsService)
private fileLeaveTimeoutID: any private fileLeaveTimeoutID: any
fileIsOver: boolean = false fileIsOver: boolean = false
hidden: boolean = true hidden: boolean = true
constructor(
private settings: SettingsService,
private toastService: ToastService,
private uploadDocumentsService: UploadDocumentsService,
private permissionsService: PermissionsService
) {}
public get dragDropEnabled(): boolean { public get dragDropEnabled(): boolean {
return ( return (
this.settings.globalDropzoneEnabled && this.settings.globalDropzoneEnabled &&

View File

@@ -1,9 +1,8 @@
import { NgClass, TitleCasePipe } from '@angular/common' import { NgClass, TitleCasePipe } from '@angular/common'
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { import {
NgbDropdownModule, NgbDropdownModule,
NgbModal,
NgbPaginationModule, NgbPaginationModule,
} from '@ng-bootstrap/ng-bootstrap' } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -12,13 +11,8 @@ import { FILTER_HAS_CORRESPONDENT_ANY } from 'src/app/data/filter-rule-type'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { SortableDirective } from 'src/app/directives/sortable.directive' import { SortableDirective } from 'src/app/directives/sortable.directive'
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { DocumentListViewService } from 'src/app/services/document-list-view.service' import { PermissionType } from 'src/app/services/permissions.service'
import {
PermissionsService,
PermissionType,
} from 'src/app/services/permissions.service'
import { CorrespondentService } from 'src/app/services/rest/correspondent.service' import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
import { ToastService } from 'src/app/services/toast.service'
import { CorrespondentEditDialogComponent } from '../../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component' import { CorrespondentEditDialogComponent } from '../../common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component' import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { ManagementListComponent } from '../management-list/management-list.component' import { ManagementListComponent } from '../management-list/management-list.component'
@@ -42,47 +36,37 @@ import { ManagementListComponent } from '../management-list/management-list.comp
], ],
}) })
export class CorrespondentListComponent extends ManagementListComponent<Correspondent> { export class CorrespondentListComponent extends ManagementListComponent<Correspondent> {
constructor( private datePipe = inject(CustomDatePipe)
correspondentsService: CorrespondentService,
modalService: NgbModal, constructor() {
toastService: ToastService, super()
documentListViewService: DocumentListViewService, this.service = inject(CorrespondentService)
permissionsService: PermissionsService, this.editDialogComponent = CorrespondentEditDialogComponent
private datePipe: CustomDatePipe this.filterRuleType = FILTER_HAS_CORRESPONDENT_ANY
) { this.typeName = $localize`correspondent`
super( this.typeNamePlural = $localize`correspondents`
correspondentsService, this.permissionType = PermissionType.Correspondent
modalService, this.extraColumns = [
CorrespondentEditDialogComponent, {
toastService, key: 'last_correspondence',
documentListViewService, name: $localize`Last used`,
permissionsService, valueFn: (c: Correspondent) => {
FILTER_HAS_CORRESPONDENT_ANY, if (c.last_correspondence) {
$localize`correspondent`, let date = new Date(c.last_correspondence)
$localize`correspondents`, if (date.toString() == 'Invalid Date') {
PermissionType.Correspondent, // very old date strings are unable to be parsed
[ date = new Date(
{ c.last_correspondence
key: 'last_correspondence', ?.toString()
name: $localize`Last used`, .replace(/([-+])(\d\d):\d\d:\d\d/gm, `$1$2:00`)
valueFn: (c: Correspondent) => { )
if (c.last_correspondence) {
let date = new Date(c.last_correspondence)
if (date.toString() == 'Invalid Date') {
// very old date strings are unable to be parsed
date = new Date(
c.last_correspondence
?.toString()
.replace(/([-+])(\d\d):\d\d:\d\d/gm, `$1$2:00`)
)
}
return this.datePipe.transform(date)
} }
return '' return this.datePipe.transform(date)
}, }
return ''
}, },
] },
) ]
} }
public reloadData(): void { public reloadData(): void {

View File

@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { import {
NgbDropdownModule, NgbDropdownModule,
NgbModal, NgbModal,
@@ -42,20 +42,16 @@ export class CustomFieldsComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit implements OnInit
{ {
public fields: CustomField[] = [] private customFieldsService = inject(CustomFieldsService)
permissionsService = inject(PermissionsService)
private modalService = inject(NgbModal)
private toastService = inject(ToastService)
private documentListViewService = inject(DocumentListViewService)
private settingsService = inject(SettingsService)
private documentService = inject(DocumentService)
private savedViewService = inject(SavedViewService)
constructor( public fields: CustomField[] = []
private customFieldsService: CustomFieldsService,
public permissionsService: PermissionsService,
private modalService: NgbModal,
private toastService: ToastService,
private documentListViewService: DocumentListViewService,
private settingsService: SettingsService,
private documentService: DocumentService,
private savedViewService: SavedViewService
) {
super()
}
ngOnInit() { ngOnInit() {
this.reload() this.reload()

View File

@@ -1,9 +1,8 @@
import { NgClass, TitleCasePipe } from '@angular/common' import { NgClass, TitleCasePipe } from '@angular/common'
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { import {
NgbDropdownModule, NgbDropdownModule,
NgbModal,
NgbPaginationModule, NgbPaginationModule,
} from '@ng-bootstrap/ng-bootstrap' } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -11,13 +10,8 @@ import { DocumentType } from 'src/app/data/document-type'
import { FILTER_HAS_DOCUMENT_TYPE_ANY } from 'src/app/data/filter-rule-type' import { FILTER_HAS_DOCUMENT_TYPE_ANY } from 'src/app/data/filter-rule-type'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { SortableDirective } from 'src/app/directives/sortable.directive' import { SortableDirective } from 'src/app/directives/sortable.directive'
import { DocumentListViewService } from 'src/app/services/document-list-view.service' import { PermissionType } from 'src/app/services/permissions.service'
import {
PermissionsService,
PermissionType,
} from 'src/app/services/permissions.service'
import { DocumentTypeService } from 'src/app/services/rest/document-type.service' import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
import { ToastService } from 'src/app/services/toast.service'
import { DocumentTypeEditDialogComponent } from '../../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component' import { DocumentTypeEditDialogComponent } from '../../common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component' import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { ManagementListComponent } from '../management-list/management-list.component' import { ManagementListComponent } from '../management-list/management-list.component'
@@ -40,26 +34,14 @@ import { ManagementListComponent } from '../management-list/management-list.comp
], ],
}) })
export class DocumentTypeListComponent extends ManagementListComponent<DocumentType> { export class DocumentTypeListComponent extends ManagementListComponent<DocumentType> {
constructor( constructor() {
documentTypeService: DocumentTypeService, super()
modalService: NgbModal, this.service = inject(DocumentTypeService)
toastService: ToastService, this.editDialogComponent = DocumentTypeEditDialogComponent
documentListViewService: DocumentListViewService, this.filterRuleType = FILTER_HAS_DOCUMENT_TYPE_ANY
permissionsService: PermissionsService this.typeName = $localize`document type`
) { this.typeNamePlural = $localize`document types`
super( this.permissionType = PermissionType.DocumentType
documentTypeService,
modalService,
DocumentTypeEditDialogComponent,
toastService,
documentListViewService,
permissionsService,
FILTER_HAS_DOCUMENT_TYPE_ANY,
$localize`document type`,
$localize`document types`,
PermissionType.DocumentType,
[]
)
} }
getDeleteMessage(object: DocumentType) { getDeleteMessage(object: DocumentType) {

View File

@@ -158,13 +158,14 @@ describe('MailComponent', () => {
it('should show errors on load if load mailAccounts failure', () => { it('should show errors on load if load mailAccounts failure', () => {
const toastErrorSpy = jest.spyOn(toastService, 'showError') const toastErrorSpy = jest.spyOn(toastService, 'showError')
jest.spyOn(mailAccountService, 'getCached').mockReturnValue(of(null))
jest jest
.spyOn(mailAccountService, 'listAll') .spyOn(mailAccountService, 'listAll')
.mockImplementation(() => .mockImplementation(() =>
throwError(() => new Error('failed to load mail accounts')) throwError(() => new Error('failed to load mail accounts'))
) )
completeSetup(mailAccountService) completeSetup(mailAccountService)
expect(toastErrorSpy).toBeCalled() expect(toastErrorSpy).toHaveBeenCalled()
}) })
it('should show errors on load if load mailRules failure', () => { it('should show errors on load if load mailRules failure', () => {
@@ -175,7 +176,7 @@ describe('MailComponent', () => {
throwError(() => new Error('failed to load mail rules')) throwError(() => new Error('failed to load mail rules'))
) )
completeSetup(mailRuleService) completeSetup(mailRuleService)
expect(toastErrorSpy).toBeCalled() expect(toastErrorSpy).toHaveBeenCalled()
}) })
it('should support edit / create mail account, show error if needed', () => { it('should support edit / create mail account, show error if needed', () => {

View File

@@ -1,5 +1,5 @@
import { AsyncPipe } from '@angular/common' import { AsyncPipe } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap'
@@ -47,6 +47,14 @@ export class MailComponent
extends ComponentWithPermissions extends ComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
mailAccountService = inject(MailAccountService)
mailRuleService = inject(MailRuleService)
private toastService = inject(ToastService)
private modalService = inject(NgbModal)
permissionsService = inject(PermissionsService)
private settingsService = inject(SettingsService)
private route = inject(ActivatedRoute)
public MailAccountType = MailAccountType public MailAccountType = MailAccountType
mailAccounts: MailAccount[] = [] mailAccounts: MailAccount[] = []
@@ -68,18 +76,6 @@ export class MailComponent
public loadingAccounts: boolean = true public loadingAccounts: boolean = true
public showAccounts: boolean = false public showAccounts: boolean = false
constructor(
public mailAccountService: MailAccountService,
public mailRuleService: MailRuleService,
private toastService: ToastService,
private modalService: NgbModal,
public permissionsService: PermissionsService,
private settingsService: SettingsService,
private route: ActivatedRoute
) {
super()
}
ngOnInit(): void { ngOnInit(): void {
this.mailAccountService this.mailAccountService
.listAll(null, null, { full_perms: true }) .listAll(null, null, { full_perms: true })

View File

@@ -1,6 +1,7 @@
import { HttpErrorResponse } from '@angular/common/http' import { HttpErrorResponse } from '@angular/common/http'
import { import {
Directive, Directive,
inject,
OnDestroy, OnDestroy,
OnInit, OnInit,
QueryList, QueryList,
@@ -59,21 +60,19 @@ export abstract class ManagementListComponent<T extends MatchingModel>
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
constructor( protected service: AbstractNameFilterService<T>
protected service: AbstractNameFilterService<T>, private modalService: NgbModal = inject(NgbModal)
private modalService: NgbModal, protected editDialogComponent: any
private editDialogComponent: any, private toastService: ToastService = inject(ToastService)
private toastService: ToastService, private documentListViewService: DocumentListViewService = inject(
private documentListViewService: DocumentListViewService, DocumentListViewService
private permissionsService: PermissionsService, )
protected filterRuleType: number, private permissionsService: PermissionsService = inject(PermissionsService)
public typeName: string, protected filterRuleType: number
public typeNamePlural: string, public typeName: string
public permissionType: PermissionType, public typeNamePlural: string
public extraColumns: ManagementListColumn[] public permissionType: PermissionType
) { public extraColumns: ManagementListColumn[]
super()
}
@ViewChildren(SortableDirective) headers: QueryList<SortableDirective> @ViewChildren(SortableDirective) headers: QueryList<SortableDirective>

View File

@@ -1,5 +1,5 @@
import { AsyncPipe } from '@angular/common' import { AsyncPipe } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { import {
FormControl, FormControl,
FormGroup, FormGroup,
@@ -40,6 +40,10 @@ export class SavedViewsComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
private savedViewService = inject(SavedViewService)
private settings = inject(SettingsService)
private toastService = inject(ToastService)
DisplayMode = DisplayMode DisplayMode = DisplayMode
public savedViews: SavedView[] public savedViews: SavedView[]
@@ -55,11 +59,7 @@ export class SavedViewsComponent
return this.settings.allDisplayFields return this.settings.allDisplayFields
} }
constructor( constructor() {
private savedViewService: SavedViewService,
private settings: SettingsService,
private toastService: ToastService
) {
super() super()
this.settings.organizingSidebarSavedViews = true this.settings.organizingSidebarSavedViews = true
} }

View File

@@ -1,9 +1,8 @@
import { NgClass, TitleCasePipe } from '@angular/common' import { NgClass, TitleCasePipe } from '@angular/common'
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { import {
NgbDropdownModule, NgbDropdownModule,
NgbModal,
NgbPaginationModule, NgbPaginationModule,
} from '@ng-bootstrap/ng-bootstrap' } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -12,13 +11,8 @@ import { StoragePath } from 'src/app/data/storage-path'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { SortableDirective } from 'src/app/directives/sortable.directive' import { SortableDirective } from 'src/app/directives/sortable.directive'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe' import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { DocumentListViewService } from 'src/app/services/document-list-view.service' import { PermissionType } from 'src/app/services/permissions.service'
import {
PermissionsService,
PermissionType,
} from 'src/app/services/permissions.service'
import { StoragePathService } from 'src/app/services/rest/storage-path.service' import { StoragePathService } from 'src/app/services/rest/storage-path.service'
import { ToastService } from 'src/app/services/toast.service'
import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component' import { StoragePathEditDialogComponent } from '../../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component' import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { ManagementListComponent } from '../management-list/management-list.component' import { ManagementListComponent } from '../management-list/management-list.component'
@@ -42,36 +36,25 @@ import { ManagementListComponent } from '../management-list/management-list.comp
], ],
}) })
export class StoragePathListComponent extends ManagementListComponent<StoragePath> { export class StoragePathListComponent extends ManagementListComponent<StoragePath> {
constructor( constructor() {
directoryService: StoragePathService, super()
modalService: NgbModal, this.service = inject(StoragePathService)
toastService: ToastService, this.editDialogComponent = StoragePathEditDialogComponent
documentListViewService: DocumentListViewService, this.filterRuleType = FILTER_HAS_STORAGE_PATH_ANY
permissionsService: PermissionsService this.typeName = $localize`storage path`
) { this.typeNamePlural = $localize`storage paths`
super( this.permissionType = PermissionType.StoragePath
directoryService, this.extraColumns = [
modalService, {
StoragePathEditDialogComponent, key: 'path',
toastService, name: $localize`Path`,
documentListViewService, rendersHtml: true,
permissionsService, hideOnMobile: true,
FILTER_HAS_STORAGE_PATH_ANY, valueFn: (c: StoragePath) => {
$localize`storage path`, return `<code>${c.path?.slice(0, 49)}${c.path?.length > 50 ? '...' : ''}</code>`
$localize`storage paths`,
PermissionType.StoragePath,
[
{
key: 'path',
name: $localize`Path`,
rendersHtml: true,
hideOnMobile: true,
valueFn: (c: StoragePath) => {
return `<code>${c.path?.slice(0, 49)}${c.path?.length > 50 ? '...' : ''}</code>`
},
}, },
] },
) ]
} }
getDeleteMessage(object: StoragePath) { getDeleteMessage(object: StoragePath) {

View File

@@ -1,9 +1,8 @@
import { NgClass, TitleCasePipe } from '@angular/common' import { NgClass, TitleCasePipe } from '@angular/common'
import { Component } from '@angular/core' import { Component, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { import {
NgbDropdownModule, NgbDropdownModule,
NgbModal,
NgbPaginationModule, NgbPaginationModule,
} from '@ng-bootstrap/ng-bootstrap' } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -12,13 +11,8 @@ import { Tag } from 'src/app/data/tag'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { SortableDirective } from 'src/app/directives/sortable.directive' import { SortableDirective } from 'src/app/directives/sortable.directive'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe' import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { DocumentListViewService } from 'src/app/services/document-list-view.service' import { PermissionType } from 'src/app/services/permissions.service'
import {
PermissionsService,
PermissionType,
} from 'src/app/services/permissions.service'
import { TagService } from 'src/app/services/rest/tag.service' import { TagService } from 'src/app/services/rest/tag.service'
import { ToastService } from 'src/app/services/toast.service'
import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component' import { TagEditDialogComponent } from '../../common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component' import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { ManagementListComponent } from '../management-list/management-list.component' import { ManagementListComponent } from '../management-list/management-list.component'
@@ -42,35 +36,24 @@ import { ManagementListComponent } from '../management-list/management-list.comp
], ],
}) })
export class TagListComponent extends ManagementListComponent<Tag> { export class TagListComponent extends ManagementListComponent<Tag> {
constructor( constructor() {
tagService: TagService, super()
modalService: NgbModal, this.service = inject(TagService)
toastService: ToastService, this.editDialogComponent = TagEditDialogComponent
documentListViewService: DocumentListViewService, this.filterRuleType = FILTER_HAS_TAGS_ALL
permissionsService: PermissionsService this.typeName = $localize`tag`
) { this.typeNamePlural = $localize`tags`
super( this.permissionType = PermissionType.Tag
tagService, this.extraColumns = [
modalService, {
TagEditDialogComponent, key: 'color',
toastService, name: $localize`Color`,
documentListViewService, rendersHtml: true,
permissionsService, valueFn: (t: Tag) => {
FILTER_HAS_TAGS_ALL, return `<span class="badge" style="color: ${t.text_color}; background-color: ${t.color}">${t.color}</span>`
$localize`tag`,
$localize`tags`,
PermissionType.Tag,
[
{
key: 'color',
name: $localize`Color`,
rendersHtml: true,
valueFn: (t: Tag) => {
return `<span class="badge" style="color: ${t.text_color}; background-color: ${t.color}">${t.color}</span>`
},
}, },
] },
) ]
} }
getDeleteMessage(object: Tag) { getDeleteMessage(object: Tag) {

View File

@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbDropdownModule, NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons' import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
@@ -34,16 +34,12 @@ export class WorkflowsComponent
extends LoadingComponentWithPermissions extends LoadingComponentWithPermissions
implements OnInit implements OnInit
{ {
public workflows: Workflow[] = [] private workflowService = inject(WorkflowService)
permissionsService = inject(PermissionsService)
private modalService = inject(NgbModal)
private toastService = inject(ToastService)
constructor( public workflows: Workflow[] = []
private workflowService: WorkflowService,
public permissionsService: PermissionsService,
private modalService: NgbModal,
private toastService: ToastService
) {
super()
}
ngOnInit() { ngOnInit() {
this.reload() this.reload()

View File

@@ -6,6 +6,7 @@ import {
OnInit, OnInit,
TemplateRef, TemplateRef,
ViewContainerRef, ViewContainerRef,
inject,
} from '@angular/core' } from '@angular/core'
import { ObjectWithPermissions } from '../data/object-with-permissions' import { ObjectWithPermissions } from '../data/object-with-permissions'
import { import {
@@ -17,6 +18,10 @@ import {
selector: '[pngxIfObjectPermissions]', selector: '[pngxIfObjectPermissions]',
}) })
export class IfObjectPermissionsDirective implements OnInit, OnChanges { export class IfObjectPermissionsDirective implements OnInit, OnChanges {
private viewContainerRef = inject(ViewContainerRef)
private templateRef = inject<TemplateRef<any>>(TemplateRef)
private permissionsService = inject(PermissionsService)
// The role the user must have // The role the user must have
@Input() @Input()
pngxIfObjectPermissions: { pngxIfObjectPermissions: {
@@ -26,17 +31,6 @@ export class IfObjectPermissionsDirective implements OnInit, OnChanges {
createdView: EmbeddedViewRef<any> createdView: EmbeddedViewRef<any>
/**
* @param {ViewContainerRef} viewContainerRef -- The location where we need to render the templateRef
* @param {TemplateRef<any>} templateRef -- The templateRef to be potentially rendered
* @param {PermissionsService} permissionsService -- Will give us access to the permissions a user has
*/
constructor(
private viewContainerRef: ViewContainerRef,
private templateRef: TemplateRef<any>,
private permissionsService: PermissionsService
) {}
public ngOnInit(): void { public ngOnInit(): void {
if ( if (
!this.pngxIfObjectPermissions?.object || !this.pngxIfObjectPermissions?.object ||

Some files were not shown because too many files have changed in this diff Show More