mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-07-29 15:24:54 +00:00
Chorehancement: update to Angular v22, 'zoneless' / 'reactive' (#13114)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Directive,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
@@ -6,12 +7,15 @@ import {
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
inject,
|
||||
} from '@angular/core'
|
||||
import { ControlValueAccessor } from '@angular/forms'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
@Directive()
|
||||
export class AbstractInputComponent<T> implements OnInit, ControlValueAccessor {
|
||||
protected readonly changeDetector = inject(ChangeDetectorRef)
|
||||
|
||||
@ViewChild('inputField')
|
||||
inputField: ElementRef
|
||||
|
||||
@@ -23,6 +27,7 @@ export class AbstractInputComponent<T> implements OnInit, ControlValueAccessor {
|
||||
|
||||
writeValue(newValue: any): void {
|
||||
this.value = newValue
|
||||
this.changeDetector.markForCheck()
|
||||
}
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn
|
||||
@@ -32,6 +37,7 @@ export class AbstractInputComponent<T> implements OnInit, ControlValueAccessor {
|
||||
}
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled
|
||||
this.changeDetector.markForCheck()
|
||||
}
|
||||
|
||||
focus() {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<ng-select name="inputId" [(ngModel)]="value"
|
||||
[disabled]="disabled"
|
||||
clearable="true"
|
||||
[items]="groups"
|
||||
[items]="groups()"
|
||||
multiple="true"
|
||||
bindLabel="name"
|
||||
bindValue="id"
|
||||
|
||||
+7
-12
@@ -1,11 +1,12 @@
|
||||
import { Component, forwardRef, inject } from '@angular/core'
|
||||
import { toSignal } from '@angular/core/rxjs-interop'
|
||||
import {
|
||||
FormsModule,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ReactiveFormsModule,
|
||||
} from '@angular/forms'
|
||||
import { NgSelectComponent } from '@ng-select/ng-select'
|
||||
import { first } from 'rxjs/operators'
|
||||
import { map } from 'rxjs/operators'
|
||||
import { Group } from 'src/app/data/group'
|
||||
import { GroupService } from 'src/app/services/rest/group.service'
|
||||
import { AbstractInputComponent } from '../../abstract-input'
|
||||
@@ -24,15 +25,9 @@ import { AbstractInputComponent } from '../../abstract-input'
|
||||
imports: [NgSelectComponent, FormsModule, ReactiveFormsModule],
|
||||
})
|
||||
export class PermissionsGroupComponent extends AbstractInputComponent<Group> {
|
||||
groups: Group[]
|
||||
|
||||
constructor() {
|
||||
const groupService = inject(GroupService)
|
||||
|
||||
super()
|
||||
groupService
|
||||
.listAll()
|
||||
.pipe(first())
|
||||
.subscribe((result) => (this.groups = result.results))
|
||||
}
|
||||
private readonly groupService = inject(GroupService)
|
||||
readonly groups = toSignal(
|
||||
this.groupService.listAll().pipe(map((result) => result.results)),
|
||||
{ initialValue: undefined as Group[] }
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<ng-select name="inputId" [(ngModel)]="value"
|
||||
[disabled]="disabled"
|
||||
clearable="true"
|
||||
[items]="users"
|
||||
[items]="users()"
|
||||
multiple="true"
|
||||
bindLabel="username"
|
||||
bindValue="id"
|
||||
|
||||
+7
-12
@@ -1,11 +1,12 @@
|
||||
import { Component, forwardRef, inject } from '@angular/core'
|
||||
import { toSignal } from '@angular/core/rxjs-interop'
|
||||
import {
|
||||
FormsModule,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ReactiveFormsModule,
|
||||
} from '@angular/forms'
|
||||
import { NgSelectComponent } from '@ng-select/ng-select'
|
||||
import { first } from 'rxjs/operators'
|
||||
import { map } from 'rxjs/operators'
|
||||
import { User } from 'src/app/data/user'
|
||||
import { UserService } from 'src/app/services/rest/user.service'
|
||||
import { AbstractInputComponent } from '../../abstract-input'
|
||||
@@ -24,15 +25,9 @@ import { AbstractInputComponent } from '../../abstract-input'
|
||||
imports: [NgSelectComponent, FormsModule, ReactiveFormsModule],
|
||||
})
|
||||
export class PermissionsUserComponent extends AbstractInputComponent<User[]> {
|
||||
users: User[]
|
||||
|
||||
constructor() {
|
||||
const userService = inject(UserService)
|
||||
|
||||
super()
|
||||
userService
|
||||
.listAll()
|
||||
.pipe(first())
|
||||
.subscribe((result) => (this.users = result.results))
|
||||
}
|
||||
private readonly userService = inject(UserService)
|
||||
readonly users = toSignal(
|
||||
this.userService.listAll().pipe(map((result) => result.results)),
|
||||
{ initialValue: undefined as User[] }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
ComponentFixture,
|
||||
TestBed,
|
||||
fakeAsync,
|
||||
tick,
|
||||
} from '@angular/core/testing'
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import {
|
||||
FormsModule,
|
||||
NG_VALUE_ACCESSOR,
|
||||
@@ -121,12 +116,14 @@ describe('SelectComponent', () => {
|
||||
).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should clear search term on blur after delay', fakeAsync(() => {
|
||||
it('should clear search term on blur after delay', () => {
|
||||
jest.useFakeTimers()
|
||||
const clearSpy = jest.spyOn(component, 'clearLastSearchTerm')
|
||||
component.onBlur()
|
||||
tick(3000)
|
||||
jest.advanceTimersByTime(3000)
|
||||
expect(clearSpy).toHaveBeenCalled()
|
||||
}))
|
||||
jest.useRealTimers()
|
||||
})
|
||||
|
||||
it('should emit filtered documents', () => {
|
||||
component.value = 10
|
||||
|
||||
@@ -106,7 +106,7 @@ describe('TagsComponent', () => {
|
||||
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
settingsService = TestBed.inject(SettingsService)
|
||||
settingsService.currentUser = { id: 1 }
|
||||
settingsService.currentUser.set({ id: 1 } as any)
|
||||
fixture = TestBed.createComponent(TagsComponent)
|
||||
fixture.debugElement.injector.get(NG_VALUE_ACCESSOR)
|
||||
component = fixture.componentInstance
|
||||
@@ -136,20 +136,13 @@ describe('TagsComponent', () => {
|
||||
})
|
||||
|
||||
it('should support create new using last search term and open a modal', () => {
|
||||
settingsService.currentUser = { id: 1 }
|
||||
settingsService.currentUser.set({ id: 1 })
|
||||
let activeInstances: NgbModalRef[]
|
||||
modalService.activeInstances.subscribe((v) => (activeInstances = v))
|
||||
component.select.filter('foobar')
|
||||
component.createTag()
|
||||
expect(modalService.hasOpenModals()).toBeTruthy()
|
||||
expect(activeInstances[0].componentInstance.object.name).toEqual('foobar')
|
||||
const editDialog = activeInstances[0]
|
||||
.componentInstance as TagEditDialogComponent
|
||||
editDialog.save() // create is mocked
|
||||
fixture.detectChanges()
|
||||
fixture.whenStable().then(() => {
|
||||
expect(fixture.debugElement.nativeElement.textContent).toContain('foobar')
|
||||
})
|
||||
})
|
||||
|
||||
it('support remove tags', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
EventEmitter,
|
||||
forwardRef,
|
||||
@@ -49,6 +50,7 @@ import { TagComponent } from '../../tag/tag.component'
|
||||
export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
private tagService = inject(TagService)
|
||||
private modalService = inject(NgbModal)
|
||||
private readonly changeDetector = inject(ChangeDetectorRef)
|
||||
|
||||
constructor() {
|
||||
this.createTagRef = this.createTag.bind(this)
|
||||
@@ -60,6 +62,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
|
||||
writeValue(newValue: number[]): void {
|
||||
this.value = newValue
|
||||
this.changeDetector.markForCheck()
|
||||
}
|
||||
registerOnChange(fn: any): void {
|
||||
this.onChange = fn
|
||||
@@ -69,11 +72,13 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
}
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled
|
||||
this.changeDetector.markForCheck()
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.tagService.listAll().subscribe((result) => {
|
||||
this.tags = result.results
|
||||
this.changeDetector.markForCheck()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -176,7 +181,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor {
|
||||
var modal = this.modalService.open(TagEditDialogComponent, {
|
||||
backdrop: 'static',
|
||||
})
|
||||
modal.componentInstance.dialogMode = EditDialogMode.CREATE
|
||||
modal.componentInstance.dialogMode.set(EditDialogMode.CREATE)
|
||||
if (name) modal.componentInstance.object = { name: name }
|
||||
else if (this.select.searchTerm)
|
||||
modal.componentInstance.object = { name: this.select.searchTerm }
|
||||
|
||||
Reference in New Issue
Block a user