Add index and classifier status
This commit is contained in:
parent
d651e3132f
commit
d56eb2eed5
@ -1540,7 +1540,7 @@
|
|||||||
<source>Error retrieving users</source>
|
<source>Error retrieving users</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">182</context>
|
<context context-type="linenumber">185</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
||||||
@ -1551,7 +1551,7 @@
|
|||||||
<source>Error retrieving groups</source>
|
<source>Error retrieving groups</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">201</context>
|
<context context-type="linenumber">204</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/users-groups/users-groups.component.ts</context>
|
||||||
@ -1562,35 +1562,35 @@
|
|||||||
<source>Saved view "<x id="PH" equiv-text="savedView.name"/>" deleted.</source>
|
<source>Saved view "<x id="PH" equiv-text="savedView.name"/>" deleted.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">414</context>
|
<context context-type="linenumber">417</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7217000812750597833" datatype="html">
|
<trans-unit id="7217000812750597833" datatype="html">
|
||||||
<source>Settings were saved successfully.</source>
|
<source>Settings were saved successfully.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">540</context>
|
<context context-type="linenumber">543</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="525012668859298131" datatype="html">
|
<trans-unit id="525012668859298131" datatype="html">
|
||||||
<source>Settings were saved successfully. Reload is required to apply some changes.</source>
|
<source>Settings were saved successfully. Reload is required to apply some changes.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">544</context>
|
<context context-type="linenumber">547</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8491974984518503778" datatype="html">
|
<trans-unit id="8491974984518503778" datatype="html">
|
||||||
<source>Reload now</source>
|
<source>Reload now</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">545</context>
|
<context context-type="linenumber">548</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="3011185103048412841" datatype="html">
|
<trans-unit id="3011185103048412841" datatype="html">
|
||||||
<source>An error occurred while saving settings.</source>
|
<source>An error occurred while saving settings.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">555</context>
|
<context context-type="linenumber">558</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context>
|
<context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context>
|
||||||
@ -1601,7 +1601,7 @@
|
|||||||
<source>Error while storing settings on server.</source>
|
<source>Error while storing settings on server.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
|
||||||
<context context-type="linenumber">589</context>
|
<context context-type="linenumber">592</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2991443309752293110" datatype="html">
|
<trans-unit id="2991443309752293110" datatype="html">
|
||||||
@ -4160,7 +4160,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">124</context>
|
<context context-type="linenumber">144</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="595732867213154214" datatype="html">
|
<trans-unit id="595732867213154214" datatype="html">
|
||||||
@ -4449,18 +4449,11 @@
|
|||||||
<context context-type="linenumber">41</context>
|
<context context-type="linenumber">41</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2375260419993138758" datatype="html">
|
|
||||||
<source>URL</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
|
||||||
<context context-type="linenumber">47</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="5611592591303869712" datatype="html">
|
<trans-unit id="5611592591303869712" datatype="html">
|
||||||
<source>Status</source>
|
<source>Status</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">49</context>
|
<context context-type="linenumber">47</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/toasts/toasts.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/toasts/toasts.component.html</context>
|
||||||
@ -4475,49 +4468,67 @@
|
|||||||
<source>Migration Status</source>
|
<source>Migration Status</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">58</context>
|
<context context-type="linenumber">56</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7881311375431899727" datatype="html">
|
<trans-unit id="7881311375431899727" datatype="html">
|
||||||
<source>Latest Migration</source>
|
<source>Latest Migration</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">66</context>
|
<context context-type="linenumber">64</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4632965004151576238" datatype="html">
|
<trans-unit id="4632965004151576238" datatype="html">
|
||||||
<source>Pending Migrations</source>
|
<source>Pending Migrations</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">68</context>
|
<context context-type="linenumber">66</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6904866445262015585" datatype="html">
|
<trans-unit id="6904866445262015585" datatype="html">
|
||||||
<source>Tasks</source>
|
<source>Tasks</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">85</context>
|
<context context-type="linenumber">83</context>
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="1044837289640087179" datatype="html">
|
|
||||||
<source>Redis URL</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
|
||||||
<context context-type="linenumber">89</context>
|
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6911698235105017958" datatype="html">
|
<trans-unit id="6911698235105017958" datatype="html">
|
||||||
<source>Redis Status</source>
|
<source>Redis Status</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">91</context>
|
<context context-type="linenumber">87</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5349496739889768589" datatype="html">
|
<trans-unit id="5349496739889768589" datatype="html">
|
||||||
<source>Celery Status</source>
|
<source>Celery Status</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
<context context-type="linenumber">100</context>
|
<context context-type="linenumber">96</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="1086740373716043695" datatype="html">
|
||||||
|
<source>Index Status</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">105</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4089509911694721896" datatype="html">
|
||||||
|
<source>Last Updated</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">115</context>
|
||||||
|
</context-group>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">127</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="5232507269140097134" datatype="html">
|
||||||
|
<source>Classifier Status</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/app/components/common/system-status-dialog/system-status-dialog.component.html</context>
|
||||||
|
<context context-type="linenumber">117</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6732151329960766506" datatype="html">
|
<trans-unit id="6732151329960766506" datatype="html">
|
||||||
|
@ -44,9 +44,9 @@ import { ConfirmButtonComponent } from '../../common/confirm-button/confirm-butt
|
|||||||
import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component'
|
import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component'
|
||||||
import { SystemStatusService } from 'src/app/services/system-status.service'
|
import { SystemStatusService } from 'src/app/services/system-status.service'
|
||||||
import {
|
import {
|
||||||
PaperlessSystemStatus,
|
SystemStatus,
|
||||||
PaperlessInstallType,
|
InstallType,
|
||||||
PaperlessConnectionStatus,
|
SystemStatusItemStatus,
|
||||||
} from 'src/app/data/system-status'
|
} from 'src/app/data/system-status'
|
||||||
|
|
||||||
const savedViews = [
|
const savedViews = [
|
||||||
@ -388,15 +388,15 @@ describe('SettingsComponent', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should load system status on initialize, show errors if needed', () => {
|
it('should load system status on initialize, show errors if needed', () => {
|
||||||
const status: PaperlessSystemStatus = {
|
const status: SystemStatus = {
|
||||||
pngx_version: '2.4.3',
|
pngx_version: '2.4.3',
|
||||||
server_os: 'macOS-14.1.1-arm64-arm-64bit',
|
server_os: 'macOS-14.1.1-arm64-arm-64bit',
|
||||||
install_type: PaperlessInstallType.BareMetal,
|
install_type: InstallType.BareMetal,
|
||||||
storage: { total: 494384795648, available: 13573525504 },
|
storage: { total: 494384795648, available: 13573525504 },
|
||||||
database: {
|
database: {
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
url: '/paperless-ngx/data/db.sqlite3',
|
url: '/paperless-ngx/data/db.sqlite3',
|
||||||
status: PaperlessConnectionStatus.ERROR,
|
status: SystemStatusItemStatus.ERROR,
|
||||||
error: null,
|
error: null,
|
||||||
migration_status: {
|
migration_status: {
|
||||||
latest_migration: 'socialaccount.0006_alter_socialaccount_extra_data',
|
latest_migration: 'socialaccount.0006_alter_socialaccount_extra_data',
|
||||||
@ -405,10 +405,16 @@ describe('SettingsComponent', () => {
|
|||||||
},
|
},
|
||||||
tasks: {
|
tasks: {
|
||||||
redis_url: 'redis://localhost:6379',
|
redis_url: 'redis://localhost:6379',
|
||||||
redis_status: PaperlessConnectionStatus.ERROR,
|
redis_status: SystemStatusItemStatus.ERROR,
|
||||||
redis_error:
|
redis_error:
|
||||||
'Error 61 connecting to localhost:6379. Connection refused.',
|
'Error 61 connecting to localhost:6379. Connection refused.',
|
||||||
celery_status: PaperlessConnectionStatus.ERROR,
|
celery_status: SystemStatusItemStatus.ERROR,
|
||||||
|
index_status: SystemStatusItemStatus.OK,
|
||||||
|
index_last_modified: new Date(),
|
||||||
|
index_error: null,
|
||||||
|
classifier_status: SystemStatusItemStatus.OK,
|
||||||
|
classifier_last_modified: new Date(),
|
||||||
|
classifier_error: null,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
jest.spyOn(systemStatusService, 'get').mockReturnValue(of(status))
|
jest.spyOn(systemStatusService, 'get').mockReturnValue(of(status))
|
||||||
@ -416,9 +422,9 @@ describe('SettingsComponent', () => {
|
|||||||
expect(component['systemStatus']).toEqual(status) // private
|
expect(component['systemStatus']).toEqual(status) // private
|
||||||
expect(component.systemStatusHasErrors).toBeTruthy()
|
expect(component.systemStatusHasErrors).toBeTruthy()
|
||||||
// coverage
|
// coverage
|
||||||
component['systemStatus'].database.status = PaperlessConnectionStatus.OK
|
component['systemStatus'].database.status = SystemStatusItemStatus.OK
|
||||||
component['systemStatus'].tasks.redis_status = PaperlessConnectionStatus.OK
|
component['systemStatus'].tasks.redis_status = SystemStatusItemStatus.OK
|
||||||
component['systemStatus'].tasks.celery_status = PaperlessConnectionStatus.OK
|
component['systemStatus'].tasks.celery_status = SystemStatusItemStatus.OK
|
||||||
expect(component.systemStatusHasErrors).toBeFalsy()
|
expect(component.systemStatusHasErrors).toBeFalsy()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ import { ComponentWithPermissions } from '../../with-permissions/with-permission
|
|||||||
import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component'
|
import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component'
|
||||||
import { SystemStatusService } from 'src/app/services/system-status.service'
|
import { SystemStatusService } from 'src/app/services/system-status.service'
|
||||||
import {
|
import {
|
||||||
PaperlessConnectionStatus,
|
SystemStatusItemStatus,
|
||||||
PaperlessSystemStatus,
|
SystemStatus,
|
||||||
} from 'src/app/data/system-status'
|
} from 'src/app/data/system-status'
|
||||||
|
|
||||||
enum SettingsNavIDs {
|
enum SettingsNavIDs {
|
||||||
@ -121,14 +121,15 @@ export class SettingsComponent
|
|||||||
users: User[]
|
users: User[]
|
||||||
groups: Group[]
|
groups: Group[]
|
||||||
|
|
||||||
private systemStatus: PaperlessSystemStatus
|
private systemStatus: SystemStatus
|
||||||
|
|
||||||
get systemStatusHasErrors(): boolean {
|
get systemStatusHasErrors(): boolean {
|
||||||
return (
|
return (
|
||||||
this.systemStatus.database.status === PaperlessConnectionStatus.ERROR ||
|
this.systemStatus.database.status === SystemStatusItemStatus.ERROR ||
|
||||||
this.systemStatus.tasks.redis_status ===
|
this.systemStatus.tasks.redis_status === SystemStatusItemStatus.ERROR ||
|
||||||
PaperlessConnectionStatus.ERROR ||
|
this.systemStatus.tasks.celery_status === SystemStatusItemStatus.ERROR ||
|
||||||
this.systemStatus.tasks.celery_status === PaperlessConnectionStatus.ERROR
|
this.systemStatus.tasks.index_status === SystemStatusItemStatus.ERROR ||
|
||||||
|
this.systemStatus.tasks.classifier_status === SystemStatusItemStatus.ERROR
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,15 +44,13 @@
|
|||||||
<dl class="card-text">
|
<dl class="card-text">
|
||||||
<dt i18n>Type</dt>
|
<dt i18n>Type</dt>
|
||||||
<dd>{{status.database.type}}</dd>
|
<dd>{{status.database.type}}</dd>
|
||||||
<dt i18n>URL</dt>
|
|
||||||
<dd>{{status.database.url}}</dd>
|
|
||||||
<dt i18n>Status</dt>
|
<dt i18n>Status</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{{status.database.status}}
|
{{status.database.status}}
|
||||||
@if (status.database.status === 'OK') {
|
@if (status.database.status === 'OK') {
|
||||||
<i-bs name="check-circle-fill" class="text-success ms-1"></i-bs>
|
<i-bs name="check-circle-fill" class="text-success ms-1" ngbPopover="{{status.database.url}}" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
} @else {
|
} @else {
|
||||||
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.database.error}}" triggers="mouseenter:mouseleave"></i-bs>
|
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.database.url}}: {{status.database.error}}" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
}
|
}
|
||||||
</dd>
|
</dd>
|
||||||
<dt i18n>Migration Status</dt>
|
<dt i18n>Migration Status</dt>
|
||||||
@ -86,15 +84,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl class="card-text">
|
<dl class="card-text">
|
||||||
<dt i18n>Redis URL</dt>
|
|
||||||
<dd>{{status.tasks.redis_url}}</dd>
|
|
||||||
<dt i18n>Redis Status</dt>
|
<dt i18n>Redis Status</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{{status.tasks.redis_status}}
|
{{status.tasks.redis_status}}
|
||||||
@if (status.tasks.redis_status === 'OK') {
|
@if (status.tasks.redis_status === 'OK') {
|
||||||
<i-bs name="check-circle-fill" class="text-success ms-1"></i-bs>
|
<i-bs name="check-circle-fill" class="text-success ms-1" ngbPopover="{{status.tasks.redis_url}}" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
} @else {
|
} @else {
|
||||||
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.redis_error}}" triggers="mouseenter:mouseleave"></i-bs>
|
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.redis_url}}: {{status.tasks.redis_error}}" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
}
|
}
|
||||||
</dd>
|
</dd>
|
||||||
<dt i18n>Celery Status</dt>
|
<dt i18n>Celery Status</dt>
|
||||||
@ -106,6 +102,30 @@
|
|||||||
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1"></i-bs>
|
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1"></i-bs>
|
||||||
}
|
}
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt i18n>Index Status</dt>
|
||||||
|
<dd>
|
||||||
|
{{status.tasks.index_status}}
|
||||||
|
@if (status.tasks.index_status === 'OK') {
|
||||||
|
<i-bs name="check-circle-fill" class="text-success ms-1" [ngbPopover]="indexStatus" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
|
} @else {
|
||||||
|
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.index_error}}" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
|
}
|
||||||
|
</dd>
|
||||||
|
<ng-template #indexStatus>
|
||||||
|
<h6><ng-container i18n>Last Updated</ng-container>:</h6> <span class="font-monospace small">{{status.tasks.index_last_modified}}</span>
|
||||||
|
</ng-template>
|
||||||
|
<dt i18n>Classifier Status</dt>
|
||||||
|
<dd>
|
||||||
|
{{status.tasks.classifier_status}}
|
||||||
|
@if (status.tasks.classifier_status === 'OK') {
|
||||||
|
<i-bs name="check-circle-fill" class="text-success ms-1" [ngbPopover]="classifierStatus" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
|
} @else {
|
||||||
|
<i-bs name="exclamation-triangle-fill" class="text-danger ms-1" ngbPopover="{{status.tasks.classifier_error}}" triggers="mouseenter:mouseleave"></i-bs>
|
||||||
|
}
|
||||||
|
</dd>
|
||||||
|
<ng-template #classifierStatus>
|
||||||
|
<h6><ng-container i18n>Last Updated</ng-container>:</h6> <span class="font-monospace small">{{status.tasks.classifier_last_modified}}</span>
|
||||||
|
</ng-template>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,29 +8,28 @@ import {
|
|||||||
NgbActiveModal,
|
NgbActiveModal,
|
||||||
NgbModalModule,
|
NgbModalModule,
|
||||||
NgbPopoverModule,
|
NgbPopoverModule,
|
||||||
|
NgbProgressbarModule,
|
||||||
} from '@ng-bootstrap/ng-bootstrap'
|
} from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'
|
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'
|
||||||
import { SystemStatusService } from 'src/app/services/system-status.service'
|
|
||||||
import { SystemStatusDialogComponent } from './system-status-dialog.component'
|
import { SystemStatusDialogComponent } from './system-status-dialog.component'
|
||||||
import { of } from 'rxjs'
|
|
||||||
import {
|
import {
|
||||||
PaperlessConnectionStatus,
|
SystemStatusItemStatus,
|
||||||
PaperlessInstallType,
|
InstallType,
|
||||||
PaperlessSystemStatus,
|
SystemStatus,
|
||||||
} from 'src/app/data/system-status'
|
} from 'src/app/data/system-status'
|
||||||
import { HttpClientTestingModule } from '@angular/common/http/testing'
|
import { HttpClientTestingModule } from '@angular/common/http/testing'
|
||||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||||
import { NgxFilesizeModule } from 'ngx-filesize'
|
import { NgxFilesizeModule } from 'ngx-filesize'
|
||||||
|
|
||||||
const status: PaperlessSystemStatus = {
|
const status: SystemStatus = {
|
||||||
pngx_version: '2.4.3',
|
pngx_version: '2.4.3',
|
||||||
server_os: 'macOS-14.1.1-arm64-arm-64bit',
|
server_os: 'macOS-14.1.1-arm64-arm-64bit',
|
||||||
install_type: PaperlessInstallType.BareMetal,
|
install_type: InstallType.BareMetal,
|
||||||
storage: { total: 494384795648, available: 13573525504 },
|
storage: { total: 494384795648, available: 13573525504 },
|
||||||
database: {
|
database: {
|
||||||
type: 'sqlite',
|
type: 'sqlite',
|
||||||
url: '/paperless-ngx/data/db.sqlite3',
|
url: '/paperless-ngx/data/db.sqlite3',
|
||||||
status: PaperlessConnectionStatus.ERROR,
|
status: SystemStatusItemStatus.ERROR,
|
||||||
error: null,
|
error: null,
|
||||||
migration_status: {
|
migration_status: {
|
||||||
latest_migration: 'socialaccount.0006_alter_socialaccount_extra_data',
|
latest_migration: 'socialaccount.0006_alter_socialaccount_extra_data',
|
||||||
@ -39,9 +38,15 @@ const status: PaperlessSystemStatus = {
|
|||||||
},
|
},
|
||||||
tasks: {
|
tasks: {
|
||||||
redis_url: 'redis://localhost:6379',
|
redis_url: 'redis://localhost:6379',
|
||||||
redis_status: PaperlessConnectionStatus.ERROR,
|
redis_status: SystemStatusItemStatus.ERROR,
|
||||||
redis_error: 'Error 61 connecting to localhost:6379. Connection refused.',
|
redis_error: 'Error 61 connecting to localhost:6379. Connection refused.',
|
||||||
celery_status: PaperlessConnectionStatus.ERROR,
|
celery_status: SystemStatusItemStatus.ERROR,
|
||||||
|
index_status: SystemStatusItemStatus.OK,
|
||||||
|
index_last_modified: new Date(),
|
||||||
|
index_error: null,
|
||||||
|
classifier_status: SystemStatusItemStatus.OK,
|
||||||
|
classifier_last_modified: new Date(),
|
||||||
|
classifier_error: null,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +66,7 @@ describe('SystemStatusDialogComponent', () => {
|
|||||||
NgxBootstrapIconsModule.pick(allIcons),
|
NgxBootstrapIconsModule.pick(allIcons),
|
||||||
NgxFilesizeModule,
|
NgxFilesizeModule,
|
||||||
NgbPopoverModule,
|
NgbPopoverModule,
|
||||||
|
NgbProgressbarModule,
|
||||||
],
|
],
|
||||||
}).compileComponents()
|
}).compileComponents()
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, Input } from '@angular/core'
|
import { Component, Input } from '@angular/core'
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { PaperlessSystemStatus } from 'src/app/data/system-status'
|
import { SystemStatus } from 'src/app/data/system-status'
|
||||||
import { SystemStatusService } from 'src/app/services/system-status.service'
|
import { SystemStatusService } from 'src/app/services/system-status.service'
|
||||||
import { Clipboard } from '@angular/cdk/clipboard'
|
import { Clipboard } from '@angular/cdk/clipboard'
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ import { Clipboard } from '@angular/cdk/clipboard'
|
|||||||
styleUrl: './system-status-dialog.component.scss',
|
styleUrl: './system-status-dialog.component.scss',
|
||||||
})
|
})
|
||||||
export class SystemStatusDialogComponent {
|
export class SystemStatusDialogComponent {
|
||||||
public status: PaperlessSystemStatus
|
public status: SystemStatus
|
||||||
|
|
||||||
public copied: boolean = false
|
public copied: boolean = false
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
export enum PaperlessInstallType {
|
export enum InstallType {
|
||||||
Containerized = 'containerized',
|
Containerized = 'containerized',
|
||||||
BareMetal = 'bare-metal',
|
BareMetal = 'bare-metal',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PaperlessConnectionStatus {
|
export enum SystemStatusItemStatus {
|
||||||
OK = 'OK',
|
OK = 'OK',
|
||||||
ERROR = 'ERROR',
|
ERROR = 'ERROR',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaperlessSystemStatus {
|
export interface SystemStatus {
|
||||||
pngx_version: string
|
pngx_version: string
|
||||||
server_os: string
|
server_os: string
|
||||||
install_type: PaperlessInstallType
|
install_type: InstallType
|
||||||
storage: {
|
storage: {
|
||||||
total: number
|
total: number
|
||||||
available: number
|
available: number
|
||||||
@ -19,7 +19,7 @@ export interface PaperlessSystemStatus {
|
|||||||
database: {
|
database: {
|
||||||
type: string
|
type: string
|
||||||
url: string
|
url: string
|
||||||
status: PaperlessConnectionStatus
|
status: SystemStatusItemStatus
|
||||||
error?: string
|
error?: string
|
||||||
migration_status: {
|
migration_status: {
|
||||||
latest_migration: string
|
latest_migration: string
|
||||||
@ -28,8 +28,14 @@ export interface PaperlessSystemStatus {
|
|||||||
}
|
}
|
||||||
tasks: {
|
tasks: {
|
||||||
redis_url: string
|
redis_url: string
|
||||||
redis_status: PaperlessConnectionStatus
|
redis_status: SystemStatusItemStatus
|
||||||
redis_error: string
|
redis_error: string
|
||||||
celery_status: PaperlessConnectionStatus
|
celery_status: SystemStatusItemStatus
|
||||||
|
index_status: SystemStatusItemStatus
|
||||||
|
index_last_modified: Date
|
||||||
|
index_error: string
|
||||||
|
classifier_status: SystemStatusItemStatus
|
||||||
|
classifier_last_modified: Date
|
||||||
|
classifier_error: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ describe('SystemStatusService', () => {
|
|||||||
httpTestingController.verify()
|
httpTestingController.verify()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls get statys endpoint', () => {
|
it('calls get status endpoint', () => {
|
||||||
service.get().subscribe()
|
service.get().subscribe()
|
||||||
const req = httpTestingController.expectOne(
|
const req = httpTestingController.expectOne(
|
||||||
`${environment.apiBaseUrl}status/`
|
`${environment.apiBaseUrl}status/`
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Observable } from 'rxjs'
|
import { Observable } from 'rxjs'
|
||||||
import { PaperlessSystemStatus } from '../data/system-status'
|
import { SystemStatus } from '../data/system-status'
|
||||||
import { environment } from 'src/environments/environment'
|
import { environment } from 'src/environments/environment'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@ -12,8 +12,8 @@ export class SystemStatusService {
|
|||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
get(): Observable<PaperlessSystemStatus> {
|
get(): Observable<SystemStatus> {
|
||||||
return this.http.get<PaperlessSystemStatus>(
|
return this.http.get<SystemStatus>(
|
||||||
`${environment.apiBaseUrl}${this.endpoint}/`
|
`${environment.apiBaseUrl}${this.endpoint}/`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import os
|
import os
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.test import override_settings
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from paperless import version
|
from paperless import version
|
||||||
|
|
||||||
|
|
||||||
class TestSystemStatusView(APITestCase):
|
class TestSystemStatus(APITestCase):
|
||||||
ENDPOINT = "/api/status/"
|
ENDPOINT = "/api/status/"
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -67,3 +69,46 @@ class TestSystemStatusView(APITestCase):
|
|||||||
response = self.client.get(self.ENDPOINT)
|
response = self.client.get(self.ENDPOINT)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data["tasks"]["celery_status"], "OK")
|
self.assertEqual(response.data["tasks"]["celery_status"], "OK")
|
||||||
|
|
||||||
|
@override_settings(INDEX_DIR="/tmp/index")
|
||||||
|
@mock.patch("whoosh.index.FileIndex.last_modified")
|
||||||
|
def test_system_status_index_ok(self, mock_last_modified):
|
||||||
|
mock_last_modified.return_value = 1707839087
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
response = self.client.get(self.ENDPOINT)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data["tasks"]["index_status"], "OK")
|
||||||
|
self.assertIsNotNone(response.data["tasks"]["index_last_modified"])
|
||||||
|
|
||||||
|
@override_settings(INDEX_DIR="/tmp/index/")
|
||||||
|
@mock.patch("documents.index.open_index", autospec=True)
|
||||||
|
def test_system_status_index_error(self, mock_open_index):
|
||||||
|
mock_open_index.return_value = None
|
||||||
|
mock_open_index.side_effect = Exception("Index error")
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
response = self.client.get(self.ENDPOINT)
|
||||||
|
mock_open_index.assert_called_once()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data["tasks"]["index_status"], "ERROR")
|
||||||
|
self.assertIsNotNone(response.data["tasks"]["index_error"])
|
||||||
|
|
||||||
|
@override_settings(MODEL_FILE="/tmp/does_not_exist")
|
||||||
|
def test_system_status_classifier_ok(self):
|
||||||
|
with open(settings.MODEL_FILE, "w") as f:
|
||||||
|
f.write("test")
|
||||||
|
f.close()
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
response = self.client.get(self.ENDPOINT)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data["tasks"]["classifier_status"], "OK")
|
||||||
|
self.assertIsNone(response.data["tasks"]["classifier_error"])
|
||||||
|
|
||||||
|
@override_settings(MODEL_FILE="/tmp/does_not_exist")
|
||||||
|
@mock.patch("documents.classifier.load_classifier")
|
||||||
|
def test_system_status_classifier_error(self, mock_load_classifier):
|
||||||
|
mock_load_classifier.side_effect = Exception("Classifier error")
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
response = self.client.get(self.ENDPOINT)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data["tasks"]["classifier_status"], "ERROR")
|
||||||
|
self.assertIsNotNone(response.data["tasks"]["classifier_error"])
|
||||||
|
@ -35,6 +35,7 @@ from django.http import HttpResponseRedirect
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
|
from django.utils.timezone import make_aware
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.decorators.cache import cache_control
|
from django.views.decorators.cache import cache_control
|
||||||
@ -66,6 +67,7 @@ from rest_framework.viewsets import ReadOnlyModelViewSet
|
|||||||
from rest_framework.viewsets import ViewSet
|
from rest_framework.viewsets import ViewSet
|
||||||
|
|
||||||
from documents import bulk_edit
|
from documents import bulk_edit
|
||||||
|
from documents import index
|
||||||
from documents.bulk_download import ArchiveOnlyStrategy
|
from documents.bulk_download import ArchiveOnlyStrategy
|
||||||
from documents.bulk_download import OriginalAndArchiveStrategy
|
from documents.bulk_download import OriginalAndArchiveStrategy
|
||||||
from documents.bulk_download import OriginalsOnlyStrategy
|
from documents.bulk_download import OriginalsOnlyStrategy
|
||||||
@ -1595,13 +1597,39 @@ class SystemStatusView(GenericAPIView, PassUserMixin):
|
|||||||
redis_error = "Error connecting to redis, check logs for more detail."
|
redis_error = "Error connecting to redis, check logs for more detail."
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ping = celery_app.control.inspect().ping()
|
celery_ping = celery_app.control.inspect().ping()
|
||||||
first_worker_ping = ping[next(iter(ping.keys()))]
|
first_worker_ping = celery_ping[next(iter(celery_ping.keys()))]
|
||||||
if first_worker_ping["ok"] == "pong":
|
if first_worker_ping["ok"] == "pong":
|
||||||
celery_active = "OK"
|
celery_active = "OK"
|
||||||
except Exception:
|
except Exception:
|
||||||
celery_active = "ERROR"
|
celery_active = "ERROR"
|
||||||
|
|
||||||
|
index_error = None
|
||||||
|
try:
|
||||||
|
ix = index.open_index()
|
||||||
|
index_status = "OK"
|
||||||
|
index_last_modified = make_aware(
|
||||||
|
datetime.fromtimestamp(ix.last_modified()),
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
index_status = "ERROR"
|
||||||
|
index_error = "Error opening index, check logs for more detail."
|
||||||
|
logger.exception(f"System status error opening index: {e}")
|
||||||
|
index_last_modified = None
|
||||||
|
|
||||||
|
classifier_error = None
|
||||||
|
try:
|
||||||
|
load_classifier()
|
||||||
|
classifier_status = "OK"
|
||||||
|
classifier_last_modified = make_aware(
|
||||||
|
datetime.fromtimestamp(os.path.getmtime(settings.MODEL_FILE)),
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
classifier_status = "ERROR"
|
||||||
|
classifier_last_modified = None
|
||||||
|
classifier_error = "Error loading classifier, check logs for more detail."
|
||||||
|
logger.exception(f"System status error loading classifier: {e}")
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
{
|
{
|
||||||
"pngx_version": current_version,
|
"pngx_version": current_version,
|
||||||
@ -1628,6 +1656,12 @@ class SystemStatusView(GenericAPIView, PassUserMixin):
|
|||||||
"redis_status": redis_status,
|
"redis_status": redis_status,
|
||||||
"redis_error": redis_error,
|
"redis_error": redis_error,
|
||||||
"celery_status": celery_active,
|
"celery_status": celery_active,
|
||||||
|
"index_status": index_status,
|
||||||
|
"index_last_modified": index_last_modified,
|
||||||
|
"index_error": index_error,
|
||||||
|
"classifier_status": classifier_status,
|
||||||
|
"classifier_last_modified": classifier_last_modified,
|
||||||
|
"classifier_error": classifier_error,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user