diff --git a/src-ui/src/app/data/websocket-document-updated-message.ts b/src-ui/src/app/data/websocket-document-updated-message.ts new file mode 100644 index 000000000..1c09a59d2 --- /dev/null +++ b/src-ui/src/app/data/websocket-document-updated-message.ts @@ -0,0 +1,7 @@ +export interface WebsocketDocumentUpdatedMessage { + document_id: number + modified?: string + owner_id?: number + users_can_view?: number[] + groups_can_view?: number[] +} diff --git a/src-ui/src/app/services/websocket-status.service.spec.ts b/src-ui/src/app/services/websocket-status.service.spec.ts index 3a4115fe6..4f34e474b 100644 --- a/src-ui/src/app/services/websocket-status.service.spec.ts +++ b/src-ui/src/app/services/websocket-status.service.spec.ts @@ -416,4 +416,25 @@ describe('ConsumerStatusService', () => { websocketStatusService.disconnect() expect(deleted).toBeTruthy() }) + + it('should trigger updated subject on document updated', () => { + let updated = false + websocketStatusService.onDocumentUpdated().subscribe((data) => { + updated = true + expect(data.document_id).toEqual(12) + }) + + websocketStatusService.connect() + server.send({ + type: WebsocketStatusType.DOCUMENT_UPDATED, + data: { + document_id: 12, + modified: '2026-02-17T00:00:00Z', + owner_id: 1, + }, + }) + + websocketStatusService.disconnect() + expect(updated).toBeTruthy() + }) }) diff --git a/src-ui/src/app/services/websocket-status.service.ts b/src-ui/src/app/services/websocket-status.service.ts index f9084c88c..e2181be97 100644 --- a/src-ui/src/app/services/websocket-status.service.ts +++ b/src-ui/src/app/services/websocket-status.service.ts @@ -2,6 +2,7 @@ import { Injectable, inject } from '@angular/core' import { Subject } from 'rxjs' import { environment } from 'src/environments/environment' import { User } from '../data/user' +import { WebsocketDocumentUpdatedMessage } from '../data/websocket-document-updated-message' import { WebsocketDocumentsDeletedMessage } from '../data/websocket-documents-deleted-message' import { WebsocketProgressMessage } from '../data/websocket-progress-message' import { SettingsService } from './settings.service' @@ -9,6 +10,7 @@ import { SettingsService } from './settings.service' export enum WebsocketStatusType { STATUS_UPDATE = 'status_update', DOCUMENTS_DELETED = 'documents_deleted', + DOCUMENT_UPDATED = 'document_updated', } // see ProgressStatusOptions in src/documents/plugins/helpers.py @@ -103,6 +105,8 @@ export class WebsocketStatusService { private documentConsumptionFinishedSubject = new Subject() private documentConsumptionFailedSubject = new Subject() private documentDeletedSubject = new Subject() + private documentUpdatedSubject = + new Subject() private connectionStatusSubject = new Subject() private get(taskId: string, filename?: string) { @@ -169,7 +173,10 @@ export class WebsocketStatusService { data: messageData, }: { type: WebsocketStatusType - data: WebsocketProgressMessage | WebsocketDocumentsDeletedMessage + data: + | WebsocketProgressMessage + | WebsocketDocumentsDeletedMessage + | WebsocketDocumentUpdatedMessage } = JSON.parse(ev.data) switch (type) { @@ -177,6 +184,12 @@ export class WebsocketStatusService { this.documentDeletedSubject.next(true) break + case WebsocketStatusType.DOCUMENT_UPDATED: + this.handleDocumentUpdated( + messageData as WebsocketDocumentUpdatedMessage + ) + break + case WebsocketStatusType.STATUS_UPDATE: this.handleProgressUpdate(messageData as WebsocketProgressMessage) break @@ -184,7 +197,11 @@ export class WebsocketStatusService { } } - private canViewMessage(messageData: WebsocketProgressMessage): boolean { + private canViewMessage(messageData: { + owner_id?: number + users_can_view?: number[] + groups_can_view?: number[] + }): boolean { // see paperless.consumers.StatusConsumer._can_view const user: User = this.settingsService.currentUser return ( @@ -244,6 +261,15 @@ export class WebsocketStatusService { } } + handleDocumentUpdated(messageData: WebsocketDocumentUpdatedMessage) { + // fallback if backend didn't restrict message + if (!this.canViewMessage(messageData)) { + return + } + + this.documentUpdatedSubject.next(messageData) + } + fail(status: FileStatus, message: string) { status.message = message status.phase = FileStatusPhase.FAILED @@ -297,6 +323,10 @@ export class WebsocketStatusService { return this.documentDeletedSubject } + onDocumentUpdated() { + return this.documentUpdatedSubject + } + onConnectionStatus() { return this.connectionStatusSubject.asObservable() }