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()