Compare commits

...

24 Commits

Author SHA1 Message Date
shamoon
af7cd8fadf Merge branch 'dev' into feature-10188-savedview-count 2025-06-27 15:16:52 -07:00
shamoon
36473838ff Coverage 2025-06-27 15:16:09 -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
shamoon
d6d419aeb0 Update app-frame.component.ts 2025-06-27 14:14:24 -07:00
shamoon
9d18382f12 Merge branch 'dev' into feature-10188-savedview-count 2025-06-27 14:13:51 -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
2db4c4c698 Add setting, trigger global refresh when needed 2025-06-22 20:07:43 -07:00
shamoon
88c6be5940 Include count badge on dashboard widgets 2025-06-22 20:07:43 -07:00
shamoon
fa1c01a732 Enhancement: show document count on sidebar saved views 2025-06-22 20:07:42 -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
213 changed files with 5053 additions and 4767 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

@@ -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

@@ -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"
@@ -221,9 +221,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,17 +11,17 @@
}, },
"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.5",
"@angular/compiler": "~19.2.14", "@angular/compiler": "~20.0.5",
"@angular/core": "~19.2.14", "@angular/core": "~20.0.5",
"@angular/forms": "~19.2.14", "@angular/forms": "~20.0.5",
"@angular/localize": "~19.2.14", "@angular/localize": "~20.0.5",
"@angular/platform-browser": "~19.2.14", "@angular/platform-browser": "~20.0.5",
"@angular/platform-browser-dynamic": "~19.2.14", "@angular/platform-browser-dynamic": "~20.0.5",
"@angular/router": "~19.2.14", "@angular/router": "~20.0.5",
"@ng-bootstrap/ng-bootstrap": "^18.0.0", "@ng-bootstrap/ng-bootstrap": "^19.0.0",
"@ng-select/ng-select": "^14.9.0", "@ng-select/ng-select": "^15.1.2",
"@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.6",
@@ -32,7 +32,7 @@
"ngx-color": "^10.0.0", "ngx-color": "^10.0.0",
"ngx-cookie-service": "^19.1.2", "ngx-cookie-service": "^19.1.2",
"ngx-device-detector": "^9.0.0", "ngx-device-detector": "^9.0.0",
"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,25 +40,25 @@
"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.5",
"@codecov/webpack-plugin": "^1.9.1", "@codecov/webpack-plugin": "^1.9.1",
"@playwright/test": "^1.51.1", "@playwright/test": "^1.51.1",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.15.29", "@types/node": "^22.15.29",
"@typescript-eslint/eslint-plugin": "^8.33.0", "@typescript-eslint/eslint-plugin": "^8.33.1",
"@typescript-eslint/parser": "^8.33.0", "@typescript-eslint/parser": "^8.33.1",
"@typescript-eslint/utils": "^8.33.0", "@typescript-eslint/utils": "^8.33.1",
"eslint": "^9.28.0", "eslint": "^9.28.0",
"jest": "29.7.0", "jest": "29.7.0",
"jest-environment-jsdom": "^29.7.0", "jest-environment-jsdom": "^29.7.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.98.0"
}, },
"pnpm": { "pnpm": {
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
@@ -77,6 +78,5 @@
"lmdb", "lmdb",
"msgpackr-extract" "msgpackr-extract"
] ]
}, }
"typings": "./src/typings.d.ts"
} }

3316
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

@@ -176,6 +176,7 @@
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<pngx-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></pngx-input-check> <pngx-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></pngx-input-check>
<pngx-input-check i18n-title title="Show document counts in sidebar saved views" formControlName="sidebarViewsShowCount"></pngx-input-check>
</div> </div>
</div> </div>

View File

@@ -31,6 +31,7 @@ import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe' import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
import { PermissionsService } from 'src/app/services/permissions.service' import { PermissionsService } from 'src/app/services/permissions.service'
import { GroupService } from 'src/app/services/rest/group.service' import { GroupService } from 'src/app/services/rest/group.service'
import { SavedViewService } from 'src/app/services/rest/saved-view.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 { SystemStatusService } from 'src/app/services/system-status.service' import { SystemStatusService } from 'src/app/services/system-status.service'
@@ -72,6 +73,7 @@ describe('SettingsComponent', () => {
let groupService: GroupService let groupService: GroupService
let modalService: NgbModal let modalService: NgbModal
let systemStatusService: SystemStatusService let systemStatusService: SystemStatusService
let savedViewsService: SavedViewService
beforeEach(async () => { beforeEach(async () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -122,6 +124,7 @@ describe('SettingsComponent', () => {
permissionsService = TestBed.inject(PermissionsService) permissionsService = TestBed.inject(PermissionsService)
modalService = TestBed.inject(NgbModal) modalService = TestBed.inject(NgbModal)
systemStatusService = TestBed.inject(SystemStatusService) systemStatusService = TestBed.inject(SystemStatusService)
savedViewsService = TestBed.inject(SavedViewService)
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true) jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
jest jest
.spyOn(permissionsService, 'currentUserHasObjectPermissions') .spyOn(permissionsService, 'currentUserHasObjectPermissions')
@@ -212,7 +215,7 @@ describe('SettingsComponent', () => {
expect(toastErrorSpy).toHaveBeenCalled() expect(toastErrorSpy).toHaveBeenCalled()
expect(storeSpy).toHaveBeenCalled() expect(storeSpy).toHaveBeenCalled()
expect(appearanceSettingsSpy).not.toHaveBeenCalled() expect(appearanceSettingsSpy).not.toHaveBeenCalled()
expect(setSpy).toHaveBeenCalledTimes(29) expect(setSpy).toHaveBeenCalledTimes(30)
// succeed // succeed
storeSpy.mockReturnValueOnce(of(true)) storeSpy.mockReturnValueOnce(of(true))
@@ -345,4 +348,14 @@ describe('SettingsComponent', () => {
component.reset() component.reset()
expect(component.settingsForm.get('themeColor').value).toEqual('') expect(component.settingsForm.get('themeColor').value).toEqual('')
}) })
it('should trigger maybeRefreshDocumentCounts on settings save', () => {
completeSetup()
const maybeRefreshSpy = jest.spyOn(
savedViewsService,
'maybeRefreshDocumentCounts'
)
settingsService.settingsSaved.emit(true)
expect(maybeRefreshSpy).toHaveBeenCalled()
})
}) })

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,
@@ -49,6 +49,7 @@ import {
PermissionsService, PermissionsService,
} from 'src/app/services/permissions.service' } from 'src/app/services/permissions.service'
import { GroupService } from 'src/app/services/rest/group.service' import { GroupService } from 'src/app/services/rest/group.service'
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
import { UserService } from 'src/app/services/rest/user.service' import { UserService } from 'src/app/services/rest/user.service'
import { import {
LanguageOption, LanguageOption,
@@ -104,6 +105,21 @@ 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)
private savedViewsService = inject(SavedViewService)
activeNavID: number activeNavID: number
settingsForm = new FormGroup({ settingsForm = new FormGroup({
@@ -138,6 +154,7 @@ export class SettingsComponent
notificationsConsumerSuppressOnDashboard: new FormControl(null), notificationsConsumerSuppressOnDashboard: new FormControl(null),
savedViewsWarnOnUnsavedChange: new FormControl(null), savedViewsWarnOnUnsavedChange: new FormControl(null),
sidebarViewsShowCount: new FormControl(null),
}) })
SettingsNavIDs = SettingsNavIDs SettingsNavIDs = SettingsNavIDs
@@ -179,24 +196,11 @@ 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()
this.savedViewsService.maybeRefreshDocumentCounts()
}) })
} }
@@ -308,6 +312,9 @@ export class SettingsComponent
savedViewsWarnOnUnsavedChange: this.settings.get( savedViewsWarnOnUnsavedChange: this.settings.get(
SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE
), ),
sidebarViewsShowCount: this.settings.get(
SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT
),
defaultPermsOwner: this.settings.get(SETTINGS_KEYS.DEFAULT_PERMS_OWNER), defaultPermsOwner: this.settings.get(SETTINGS_KEYS.DEFAULT_PERMS_OWNER),
defaultPermsViewUsers: this.settings.get( defaultPermsViewUsers: this.settings.get(
SETTINGS_KEYS.DEFAULT_PERMS_VIEW_USERS SETTINGS_KEYS.DEFAULT_PERMS_VIEW_USERS
@@ -485,6 +492,10 @@ export class SettingsComponent
SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE, SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE,
this.settingsForm.value.savedViewsWarnOnUnsavedChange this.settingsForm.value.savedViewsWarnOnUnsavedChange
) )
this.settings.set(
SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT,
this.settingsForm.value.sidebarViewsShowCount
)
this.settings.set( this.settings.set(
SETTINGS_KEYS.DEFAULT_PERMS_OWNER, SETTINGS_KEYS.DEFAULT_PERMS_OWNER,
this.settingsForm.value.defaultPermsOwner this.settingsForm.value.defaultPermsOwner

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

@@ -112,7 +112,14 @@
routerLinkActive="active" (click)="closeMenu()" [ngbPopover]="view.name" routerLinkActive="active" (click)="closeMenu()" [ngbPopover]="view.name"
[disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave"
popoverClass="popover-slim"> popoverClass="popover-slim">
<i-bs class="me-1" name="funnel"></i-bs><span>&nbsp;{{view.name}}</span> <i-bs class="me-1" name="funnel"></i-bs><span>&nbsp;{{view.name}}
@if (showSidebarCounts && !slimSidebarEnabled) {
<span><span class="badge bg-info text-dark ms-2 d-inline">{{ savedViewService.getDocumentCount(view) }}</span></span>
}
</span>
@if (showSidebarCounts && slimSidebarEnabled) {
<span class="badge bg-info text-dark position-absolute top-0 end-0 d-none d-md-block">{{ savedViewService.getDocumentCount(view) }}</span>
}
</a> </a>
@if (settingsService.organizingSidebarSavedViews) { @if (settingsService.organizingSidebarSavedViews) {
<div class="position-absolute end-0 top-0 px-3 py-2" [class.me-n3]="slimSidebarEnabled" cdkDragHandle> <div class="position-absolute end-0 top-0 px-3 py-2" [class.me-n3]="slimSidebarEnabled" cdkDragHandle>

View File

@@ -92,6 +92,7 @@ describe('AppFrameComponent', () => {
let router: Router let router: Router
let savedViewSpy let savedViewSpy
let modalService: NgbModal let modalService: NgbModal
let maybeRefreshSpy
beforeEach(async () => { beforeEach(async () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -113,7 +114,11 @@ describe('AppFrameComponent', () => {
{ {
provide: SavedViewService, provide: SavedViewService,
useValue: { useValue: {
reload: () => {}, reload: (fn: any) => {
if (fn) {
fn()
}
},
listAll: () => listAll: () =>
of({ of({
all: [saved_views.map((v) => v.id)], all: [saved_views.map((v) => v.id)],
@@ -121,6 +126,8 @@ describe('AppFrameComponent', () => {
results: saved_views, results: saved_views,
}), }),
sidebarViews: saved_views.filter((v) => v.show_in_sidebar), sidebarViews: saved_views.filter((v) => v.show_in_sidebar),
getDocumentCount: (view: SavedView) => 5,
maybeRefreshDocumentCounts: () => {},
}, },
}, },
PermissionsService, PermissionsService,
@@ -169,6 +176,7 @@ describe('AppFrameComponent', () => {
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true) jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
savedViewSpy = jest.spyOn(savedViewService, 'reload') savedViewSpy = jest.spyOn(savedViewService, 'reload')
maybeRefreshSpy = jest.spyOn(savedViewService, 'maybeRefreshDocumentCounts')
fixture = TestBed.createComponent(AppFrameComponent) fixture = TestBed.createComponent(AppFrameComponent)
component = fixture.componentInstance component = fixture.componentInstance
@@ -359,4 +367,8 @@ describe('AppFrameComponent', () => {
expect(toastErrorSpy).toHaveBeenCalledTimes(2) expect(toastErrorSpy).toHaveBeenCalledTimes(2)
expect(toastInfoSpy).toHaveBeenCalledTimes(3) expect(toastInfoSpy).toHaveBeenCalledTimes(3)
}) })
it('should call maybeRefreshDocumentCounts after saved views reload', () => {
expect(maybeRefreshSpy).toHaveBeenCalled()
})
}) })

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(
@@ -101,7 +102,9 @@ export class AppFrameComponent
PermissionType.SavedView PermissionType.SavedView
) )
) { ) {
this.savedViewService.reload() this.savedViewService.reload(() => {
this.savedViewService.maybeRefreshDocumentCounts()
})
} }
} }
@@ -282,4 +285,8 @@ export class AppFrameComponent
onLogout() { onLogout() {
this.openDocumentsService.closeAll() this.openDocumentsService.closeAll()
} }
get showSidebarCounts(): boolean {
return this.settingsService.get(SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT)
}
} }

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 @@
<pngx-widget-frame <pngx-widget-frame
*pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }"
[title]="savedView.name" [title]="savedView.name"
[badge]="count"
[loading]="loading" [loading]="loading"
[draggable]="savedView" [draggable]="savedView"
> >

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
@@ -121,6 +118,8 @@ export class SavedViewWidgetComponent
displayFields: DisplayField[] = DEFAULT_DASHBOARD_DISPLAY_FIELDS displayFields: DisplayField[] = DEFAULT_DASHBOARD_DISPLAY_FIELDS
count: number
ngOnInit(): void { ngOnInit(): void {
this.reload() this.reload()
this.displayMode = this.savedView.display_mode ?? DisplayMode.TABLE this.displayMode = this.savedView.display_mode ?? DisplayMode.TABLE
@@ -181,6 +180,7 @@ export class SavedViewWidgetComponent
tap((result) => { tap((result) => {
this.show = true this.show = true
this.documents = result.results this.documents = result.results
this.count = result.count
}), }),
delay(500) delay(500)
) )

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

@@ -2,13 +2,16 @@
<div class="card shadow-sm bg-light fade" [class.show]="show" cdkDrag [cdkDragDisabled]="!draggable" cdkDragPreviewContainer="parent"> <div class="card shadow-sm bg-light fade" [class.show]="show" cdkDrag [cdkDragDisabled]="!draggable" cdkDragPreviewContainer="parent">
<div class="card-header"> <div class="card-header">
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<div class="d-flex"> <div class="d-flex align-items-center">
@if (draggable) { @if (draggable) {
<div class="ms-n2 me-1" cdkDragHandle> <div class="ms-n2 me-1" cdkDragHandle>
<i-bs name="grip-vertical"></i-bs> <i-bs name="grip-vertical"></i-bs>
</div> </div>
} }
<h6 class="card-title mb-0">{{title}}</h6> <h6 class="card-title mb-0">{{title}}</h6>
@if (badge) {
<span class="badge bg-info text-dark ms-2">{{badge}}</span>
}
</div> </div>
@if (loading) { @if (loading) {
<div class="spinner-border spinner-border-sm fw-normal ms-2 me-auto" role="status"></div> <div class="spinner-border spinner-border-sm fw-normal ms-2 me-auto" role="status"></div>

View File

@@ -30,6 +30,9 @@ export class WidgetFrameComponent
@Input() @Input()
cardless: boolean = false cardless: boolean = false
@Input()
badge: string
ngAfterViewInit(): void { ngAfterViewInit(): void {
setTimeout(() => { setTimeout(() => {
this.show = true this.show = true

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,
@@ -73,6 +73,7 @@ import { CorrespondentService } from 'src/app/services/rest/correspondent.servic
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service' import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
import { DocumentTypeService } from 'src/app/services/rest/document-type.service' import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
import { DocumentService } from 'src/app/services/rest/document.service' import { DocumentService } from 'src/app/services/rest/document.service'
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
import { StoragePathService } from 'src/app/services/rest/storage-path.service' import { StoragePathService } from 'src/app/services/rest/storage-path.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'
@@ -176,6 +177,27 @@ 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)
private savedViewService = inject(SavedViewService)
@ViewChild('inputTitle') @ViewChild('inputTitle')
titleInput: TextComponent titleInput: TextComponent
@@ -259,30 +281,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)
} }
@@ -845,6 +843,7 @@ export class DocumentDetailComponent
} else { } else {
this.openDocumentService.refreshDocument(this.documentId) this.openDocumentService.refreshDocument(this.documentId)
} }
this.savedViewService.maybeRefreshDocumentCounts()
}, },
error: (error) => { error: (error) => {
this.networkActive = false this.networkActive = false
@@ -1192,6 +1191,7 @@ export class DocumentDetailComponent
notesUpdated(notes: DocumentNote[]) { notesUpdated(notes: DocumentNote[]) {
this.document.notes = notes this.document.notes = notes
this.openDocumentService.refreshDocument(this.documentId) this.openDocumentService.refreshDocument(this.documentId)
this.savedViewService.maybeRefreshDocumentCounts()
} }
get userIsOwner(): boolean { get userIsOwner(): boolean {

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,
@@ -32,6 +32,7 @@ import {
DocumentService, DocumentService,
SelectionDataItem, SelectionDataItem,
} from 'src/app/services/rest/document.service' } from 'src/app/services/rest/document.service'
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
import { StoragePathService } from 'src/app/services/rest/storage-path.service' import { StoragePathService } from 'src/app/services/rest/storage-path.service'
import { TagService } from 'src/app/services/rest/tag.service' import { TagService } from 'src/app/services/rest/tag.service'
import { SettingsService } from 'src/app/services/settings.service' import { SettingsService } from 'src/app/services/settings.service'
@@ -71,6 +72,20 @@ 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)
private savedViewService = inject(SavedViewService)
tagSelectionModel = new FilterableDropdownSelectionModel(true) tagSelectionModel = new FilterableDropdownSelectionModel(true)
correspondentSelectionModel = new FilterableDropdownSelectionModel() correspondentSelectionModel = new FilterableDropdownSelectionModel()
documentTypeSelectionModel = new FilterableDropdownSelectionModel() documentTypeSelectionModel = new FilterableDropdownSelectionModel()
@@ -94,23 +109,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
) )
@@ -274,6 +272,7 @@ export class BulkEditorComponent
this.list.selected.forEach((id) => { this.list.selected.forEach((id) => {
this.openDocumentService.refreshDocument(id) this.openDocumentService.refreshDocument(id)
}) })
this.savedViewService.maybeRefreshDocumentCounts()
if (modal) { if (modal) {
modal.close() modal.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
} }

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