Add alert badge to button if errors
This commit is contained in:
parent
c40b2adad7
commit
4f4a7aee14
@ -7,11 +7,20 @@
|
||||
<button class="btn btn-sm btn-outline-primary" (click)="tourService.start()">
|
||||
<i-bs class="me-1" name="airplane"></i-bs> <ng-container i18n>Start tour</ng-container>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary ms-5" (click)="showSystemStatus()"
|
||||
<button class="btn btn-sm btn-outline-primary position-relative ms-5" (click)="showSystemStatus()"
|
||||
[disabled]="!systemStatus"
|
||||
*pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Admin }">
|
||||
<i-bs class="me-1" name="card-checklist"></i-bs> <ng-container i18n>System Status</ng-container>
|
||||
@if (!systemStatus) {
|
||||
<div class="spinner-border spinner-border-sm me-1" role="status"></div>
|
||||
} @else {
|
||||
<i-bs class="me-1" name="card-checklist"></i-bs>
|
||||
@if (systemStatusHasErrors) {
|
||||
<span class="badge bg-danger position-absolute top-0 start-100 translate-middle rounded-pill py-1 px-2">!</span>
|
||||
}
|
||||
}
|
||||
<ng-container i18n>System Status</ng-container>
|
||||
</button>
|
||||
<a *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Admin }" class="btn btn-sm btn-primary ms-2" href="admin/" target="_blank">
|
||||
<a *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Admin }" class="btn btn-sm btn-primary ms-3" href="admin/" target="_blank">
|
||||
<ng-container i18n>Open Django Admin</ng-container>
|
||||
<i-bs name="arrow-up-right"></i-bs>
|
||||
</a>
|
||||
|
@ -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()
|
||||
|
@ -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, {
|
||||
const modal: NgbModalRef = this.modalService.open(
|
||||
SystemStatusDialogComponent,
|
||||
{
|
||||
size: 'xl',
|
||||
})
|
||||
}
|
||||
)
|
||||
modal.componentInstance.status = this.systemStatus
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,7 @@ const status: PaperlessSystemStatus = {
|
||||
describe('SystemStatusDialogComponent', () => {
|
||||
let component: SystemStatusDialogComponent
|
||||
let fixture: ComponentFixture<SystemStatusDialogComponent>
|
||||
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()
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user