From 4f4a7aee14ae6e839a289b5327f19993a724379c Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 12 Feb 2024 10:43:52 -0800 Subject: [PATCH] Add alert badge to button if errors --- .../admin/settings/settings.component.html | 15 ++++-- .../admin/settings/settings.component.spec.ts | 38 +++++++++++++++ .../admin/settings/settings.component.ts | 46 +++++++++++++++++-- .../system-status-dialog.component.spec.ts | 12 +---- .../system-status-dialog.component.ts | 9 +--- 5 files changed, 94 insertions(+), 26 deletions(-) diff --git a/src-ui/src/app/components/admin/settings/settings.component.html b/src-ui/src/app/components/admin/settings/settings.component.html index e448de7f8..c1fff6e12 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.html +++ b/src-ui/src/app/components/admin/settings/settings.component.html @@ -7,11 +7,20 @@ - - + Open Django Admin   diff --git a/src-ui/src/app/components/admin/settings/settings.component.spec.ts b/src-ui/src/app/components/admin/settings/settings.component.spec.ts index d5b681394..e93de6e10 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.spec.ts +++ b/src-ui/src/app/components/admin/settings/settings.component.spec.ts @@ -42,6 +42,12 @@ import { IfOwnerDirective } from 'src/app/directives/if-owner.directive' import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons' import { ConfirmButtonComponent } from '../../common/confirm-button/confirm-button.component' import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component' +import { SystemStatusService } from 'src/app/services/system-status.service' +import { + PaperlessSystemStatus, + PaperlessInstallType, + PaperlessConnectionStatus, +} from 'src/app/data/system-status' const savedViews = [ { id: 1, name: 'view1', show_in_sidebar: true, show_on_dashboard: true }, @@ -69,6 +75,7 @@ describe('SettingsComponent', () => { let permissionsService: PermissionsService let groupService: GroupService let modalService: NgbModal + let systemStatusService: SystemStatusService beforeEach(async () => { TestBed.configureTestingModule({ @@ -113,6 +120,7 @@ describe('SettingsComponent', () => { userService = TestBed.inject(UserService) permissionsService = TestBed.inject(PermissionsService) modalService = TestBed.inject(NgbModal) + systemStatusService = TestBed.inject(SystemStatusService) jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true) jest .spyOn(permissionsService, 'currentUserHasObjectPermissions') @@ -379,6 +387,36 @@ describe('SettingsComponent', () => { expect(toastErrorSpy).toBeCalled() }) + it('should load system status on initialize, show errors if needed', () => { + const status: PaperlessSystemStatus = { + pngx_version: '2.4.3', + server_os: 'macOS-14.1.1-arm64-arm-64bit', + install_type: PaperlessInstallType.BareMetal, + storage: { total: 494384795648, available: 13573525504 }, + database: { + type: 'sqlite', + url: '/paperless-ngx/data/db.sqlite3', + status: PaperlessConnectionStatus.ERROR, + error: null, + migration_status: { + latest_migration: 'socialaccount.0006_alter_socialaccount_extra_data', + unapplied_migrations: [], + }, + }, + tasks: { + redis_url: 'redis://localhost:6379', + redis_status: PaperlessConnectionStatus.ERROR, + redis_error: + 'Error 61 connecting to localhost:6379. Connection refused.', + celery_status: PaperlessConnectionStatus.ERROR, + }, + } + jest.spyOn(systemStatusService, 'get').mockReturnValue(of(status)) + completeSetup() + expect(component['systemStatus']).toEqual(status) // private + expect(component.systemStatusHasErrors).toBeTruthy() + }) + it('should open system status dialog', () => { const modalOpenSpy = jest.spyOn(modalService, 'open') completeSetup() diff --git a/src-ui/src/app/components/admin/settings/settings.component.ts b/src-ui/src/app/components/admin/settings/settings.component.ts index 053d72ccb..7fe5320e3 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.ts +++ b/src-ui/src/app/components/admin/settings/settings.component.ts @@ -9,7 +9,11 @@ import { } from '@angular/core' import { FormGroup, FormControl } from '@angular/forms' import { ActivatedRoute, Router } from '@angular/router' -import { NgbModal, NgbNavChangeEvent } from '@ng-bootstrap/ng-bootstrap' +import { + NgbModal, + NgbModalRef, + NgbNavChangeEvent, +} from '@ng-bootstrap/ng-bootstrap' import { DirtyComponent, dirtyCheck } from '@ngneat/dirty-check-forms' import { TourService } from 'ngx-ui-tour-ng-bootstrap' import { @@ -41,6 +45,11 @@ import { import { ToastService, Toast } from 'src/app/services/toast.service' import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component' import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component' +import { SystemStatusService } from 'src/app/services/system-status.service' +import { + PaperlessConnectionStatus, + PaperlessSystemStatus, +} from 'src/app/data/system-status' enum SettingsNavIDs { General = 1, @@ -112,6 +121,17 @@ export class SettingsComponent users: User[] groups: Group[] + private systemStatus: PaperlessSystemStatus + + get systemStatusHasErrors(): boolean { + return ( + this.systemStatus.database.status === PaperlessConnectionStatus.ERROR || + this.systemStatus.tasks.redis_status === + PaperlessConnectionStatus.ERROR || + this.systemStatus.tasks.celery_status === PaperlessConnectionStatus.ERROR + ) + } + get computedDateLocale(): string { return ( this.settingsForm.value.dateLocale || @@ -133,7 +153,8 @@ export class SettingsComponent private groupsService: GroupService, private router: Router, public permissionsService: PermissionsService, - private modalService: NgbModal + private modalService: NgbModal, + private systemStatusService: SystemStatusService ) { super() this.settings.settingsSaved.subscribe(() => { @@ -362,6 +383,17 @@ export class SettingsComponent // prevents loss of unsaved changes this.settingsForm.patchValue(currentFormValue) } + + if ( + this.permissionsService.currentUserCan( + PermissionAction.View, + PermissionType.Admin + ) + ) { + this.systemStatusService.get().subscribe((status) => { + this.systemStatus = status + }) + } } private emptyGroup(group: FormGroup) { @@ -569,8 +601,12 @@ export class SettingsComponent } showSystemStatus() { - this.modalService.open(SystemStatusDialogComponent, { - size: 'xl', - }) + const modal: NgbModalRef = this.modalService.open( + SystemStatusDialogComponent, + { + size: 'xl', + } + ) + modal.componentInstance.status = this.systemStatus } } diff --git a/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.spec.ts b/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.spec.ts index 248675a1c..413f34be1 100644 --- a/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.spec.ts @@ -48,9 +48,7 @@ const status: PaperlessSystemStatus = { describe('SystemStatusDialogComponent', () => { let component: SystemStatusDialogComponent let fixture: ComponentFixture - let systemStatusService: SystemStatusService let clipboard: Clipboard - let getStatusSpy beforeEach(async () => { await TestBed.configureTestingModule({ @@ -66,21 +64,13 @@ describe('SystemStatusDialogComponent', () => { ], }).compileComponents() - systemStatusService = TestBed.inject(SystemStatusService) - getStatusSpy = jest - .spyOn(systemStatusService, 'get') - .mockReturnValue(of(status)) fixture = TestBed.createComponent(SystemStatusDialogComponent) component = fixture.componentInstance + component.status = status clipboard = TestBed.inject(Clipboard) fixture.detectChanges() }) - it('should subscribe to system status service', () => { - expect(getStatusSpy).toHaveBeenCalled() - expect(component.status).toEqual(status) - }) - it('should close the active modal', () => { const closeSpy = jest.spyOn(component.activeModal, 'close') component.close() diff --git a/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.ts b/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.ts index 81e88200e..26948aa3f 100644 --- a/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.ts +++ b/src-ui/src/app/components/common/system-status-dialog/system-status-dialog.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core' +import { Component, Input } from '@angular/core' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' import { PaperlessSystemStatus } from 'src/app/data/system-status' import { SystemStatusService } from 'src/app/services/system-status.service' @@ -16,13 +16,8 @@ export class SystemStatusDialogComponent { constructor( public activeModal: NgbActiveModal, - private systemStatusService: SystemStatusService, private clipboard: Clipboard - ) { - this.systemStatusService.get().subscribe((status) => { - this.status = status - }) - } + ) {} public close() { this.activeModal.close()