mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-07-11 14:35:09 +00:00
Chorehancement: update to Angular v22, 'zoneless' / 'reactive' (#13114)
This commit is contained in:
@@ -9,8 +9,8 @@
|
||||
</button>
|
||||
@if (canViewSystemStatus) {
|
||||
<button class="btn btn-sm btn-outline-primary position-relative ms-md-5 me-1" (click)="showSystemStatus()"
|
||||
[disabled]="!systemStatus">
|
||||
@if (!systemStatus) {
|
||||
[disabled]="!systemStatus()">
|
||||
@if (!systemStatus()) {
|
||||
<div class="spinner-border spinner-border-sm me-2 h-75" role="status"></div>
|
||||
} @else {
|
||||
<i-bs class="me-2" name="card-checklist"></i-bs>
|
||||
@@ -313,7 +313,7 @@
|
||||
<span i18n>Default Owner</span>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<pngx-input-select [items]="users" bindLabel="username" formControlName="defaultPermsOwner" [allowNull]="true"></pngx-input-select>
|
||||
<pngx-input-select [items]="users()" bindLabel="username" formControlName="defaultPermsOwner" [allowNull]="true"></pngx-input-select>
|
||||
<small class="form-text text-muted text-end d-block mt-n2" i18n>Objects without an owner can be viewed and edited by all users</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -99,6 +99,13 @@ const status: SystemStatus = {
|
||||
llmindex_status: SystemStatusItemStatus.DISABLED,
|
||||
llmindex_last_modified: new Date().toISOString(),
|
||||
llmindex_error: null,
|
||||
summary: {
|
||||
days: 30,
|
||||
total_count: 12,
|
||||
pending_count: 1,
|
||||
success_count: 10,
|
||||
failure_count: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -161,7 +168,7 @@ describe('SettingsComponent', () => {
|
||||
viewportScroller = TestBed.inject(ViewportScroller)
|
||||
toastService = TestBed.inject(ToastService)
|
||||
settingsService = TestBed.inject(SettingsService)
|
||||
settingsService.currentUser = users[0]
|
||||
settingsService.currentUser.set(users[0])
|
||||
userService = TestBed.inject(UserService)
|
||||
permissionsService = TestBed.inject(PermissionsService)
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
@@ -202,7 +209,7 @@ describe('SettingsComponent', () => {
|
||||
fixture.detectChanges()
|
||||
}
|
||||
|
||||
it('should support tabbed settings & change URL, prevent navigation if dirty confirmation rejected', () => {
|
||||
it('should support tabbed settings & change URL, prevent navigation if dirty confirmation rejected', async () => {
|
||||
completeSetup()
|
||||
const navigateSpy = jest.spyOn(router, 'navigate')
|
||||
const tabButtons = fixture.debugElement.queryAll(By.directive(NgbNavLink))
|
||||
@@ -210,16 +217,19 @@ describe('SettingsComponent', () => {
|
||||
expect(navigateSpy).toHaveBeenCalledWith(['settings', 'documents'])
|
||||
tabButtons[2].nativeElement.dispatchEvent(new MouseEvent('click'))
|
||||
expect(navigateSpy).toHaveBeenCalledWith(['settings', 'permissions'])
|
||||
await fixture.whenStable()
|
||||
|
||||
const initSpy = jest.spyOn(component, 'initialize')
|
||||
component.isDirty = true // mock dirty
|
||||
navigateSpy.mockResolvedValueOnce(false) // nav rejected cause dirty
|
||||
tabButtons[0].nativeElement.dispatchEvent(new MouseEvent('click'))
|
||||
await fixture.whenStable()
|
||||
expect(navigateSpy).toHaveBeenCalledWith(['settings', 'general'])
|
||||
expect(initSpy).not.toHaveBeenCalled()
|
||||
|
||||
navigateSpy.mockResolvedValueOnce(true) // nav accepted even though dirty
|
||||
tabButtons[2].nativeElement.dispatchEvent(new MouseEvent('click'))
|
||||
await fixture.whenStable()
|
||||
expect(navigateSpy).toHaveBeenCalledWith(['settings', 'permissions'])
|
||||
expect(initSpy).toHaveBeenCalled()
|
||||
})
|
||||
@@ -340,13 +350,13 @@ describe('SettingsComponent', () => {
|
||||
type === PermissionType.SystemMonitoring
|
||||
)
|
||||
completeSetup()
|
||||
expect(component['systemStatus']).toEqual(status) // private
|
||||
expect(component.systemStatus()).toEqual(status)
|
||||
expect(component.systemStatusHasErrors).toBeTruthy()
|
||||
// coverage
|
||||
component['systemStatus'].database.status = SystemStatusItemStatus.OK
|
||||
component['systemStatus'].tasks.redis_status = SystemStatusItemStatus.OK
|
||||
component['systemStatus'].tasks.celery_status = SystemStatusItemStatus.OK
|
||||
component['systemStatus'].tasks.sanity_check_status =
|
||||
component.systemStatus().database.status = SystemStatusItemStatus.OK
|
||||
component.systemStatus().tasks.redis_status = SystemStatusItemStatus.OK
|
||||
component.systemStatus().tasks.celery_status = SystemStatusItemStatus.OK
|
||||
component.systemStatus().tasks.sanity_check_status =
|
||||
SystemStatusItemStatus.OK
|
||||
expect(component.systemStatusHasErrors).toBeFalsy()
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core'
|
||||
import {
|
||||
FormControl,
|
||||
@@ -189,10 +190,10 @@ export class SettingsComponent
|
||||
unsubscribeNotifier: Subject<any> = new Subject()
|
||||
savePending: boolean = false
|
||||
|
||||
users: User[]
|
||||
groups: Group[]
|
||||
readonly users = signal<User[]>(undefined)
|
||||
readonly groups = signal<Group[]>(undefined)
|
||||
|
||||
public systemStatus: SystemStatus
|
||||
public readonly systemStatus = signal<SystemStatus>(undefined)
|
||||
|
||||
public readonly GlobalSearchType = GlobalSearchType
|
||||
|
||||
@@ -203,16 +204,18 @@ export class SettingsComponent
|
||||
public readonly documentDetailFieldOptions = documentDetailFieldOptions
|
||||
|
||||
get systemStatusHasErrors(): boolean {
|
||||
const status = this.systemStatus()
|
||||
if (!status) {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
this.systemStatus.database.status === SystemStatusItemStatus.ERROR ||
|
||||
this.systemStatus.tasks.redis_status === SystemStatusItemStatus.ERROR ||
|
||||
this.systemStatus.tasks.celery_status === SystemStatusItemStatus.ERROR ||
|
||||
this.systemStatus.tasks.index_status === SystemStatusItemStatus.ERROR ||
|
||||
this.systemStatus.tasks.classifier_status ===
|
||||
SystemStatusItemStatus.ERROR ||
|
||||
this.systemStatus.tasks.sanity_check_status ===
|
||||
SystemStatusItemStatus.ERROR ||
|
||||
this.systemStatus.websocket_connected === SystemStatusItemStatus.ERROR
|
||||
status.database.status === SystemStatusItemStatus.ERROR ||
|
||||
status.tasks.redis_status === SystemStatusItemStatus.ERROR ||
|
||||
status.tasks.celery_status === SystemStatusItemStatus.ERROR ||
|
||||
status.tasks.index_status === SystemStatusItemStatus.ERROR ||
|
||||
status.tasks.classifier_status === SystemStatusItemStatus.ERROR ||
|
||||
status.tasks.sanity_check_status === SystemStatusItemStatus.ERROR ||
|
||||
status.websocket_connected === SystemStatusItemStatus.ERROR
|
||||
)
|
||||
}
|
||||
|
||||
@@ -246,7 +249,7 @@ export class SettingsComponent
|
||||
.pipe(first())
|
||||
.subscribe({
|
||||
next: (r) => {
|
||||
this.users = r.results
|
||||
this.users.set(r.results)
|
||||
},
|
||||
error: (e) => {
|
||||
this.toastService.showError($localize`Error retrieving users`, e)
|
||||
@@ -265,7 +268,7 @@ export class SettingsComponent
|
||||
.pipe(first())
|
||||
.subscribe({
|
||||
next: (r) => {
|
||||
this.groups = r.results
|
||||
this.groups.set(r.results)
|
||||
},
|
||||
error: (e) => {
|
||||
this.toastService.showError($localize`Error retrieving groups`, e)
|
||||
@@ -431,7 +434,7 @@ export class SettingsComponent
|
||||
|
||||
if (this.canViewSystemStatus) {
|
||||
this.systemStatusService.get().subscribe((status) => {
|
||||
this.systemStatus = status
|
||||
this.systemStatus.set(status)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -664,6 +667,6 @@ export class SettingsComponent
|
||||
size: 'xl',
|
||||
}
|
||||
)
|
||||
modal.componentInstance.status = this.systemStatus
|
||||
modal.componentInstance.status.set(this.systemStatus())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user