From 3fab83dff8e720e50547ca7c7018e7fbe3d1b5dc Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 10 Aug 2026 10:57:35 -0700 Subject: [PATCH] Frotnend workflow stuff --- .../workflow-edit-dialog.component.html | 7 ++ .../workflow-edit-dialog.component.spec.ts | 81 ++++++++++++++++++- .../workflow-edit-dialog.component.ts | 43 +++++++--- src-ui/src/app/data/workflow-action.ts | 1 + 4 files changed, 120 insertions(+), 12 deletions(-) diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html index 0e3329ea3..3827c41e6 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html @@ -455,6 +455,13 @@ } + @case (WorkflowActionType.RemoteOcr) { +
+
+

The document will be sent to the configured remote OCR service. May incur costs.

+
+
+ } } diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts index bc7be5fad..814525751 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts @@ -29,6 +29,7 @@ import { DocumentSource, WorkflowTriggerType, } from 'src/app/data/workflow-trigger' +import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { IfOwnerDirective } from 'src/app/directives/if-owner.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { CorrespondentService } from 'src/app/services/rest/correspondent.service' @@ -224,7 +225,12 @@ describe('WorkflowEditDialogComponent', () => { ).toEqual('Document Added') expect(component.getTriggerTypeOptionName(null)).toEqual('') expect(component.sourceOptions).toEqual(DOCUMENT_SOURCE_OPTIONS) - expect(component.actionTypeOptions).toEqual(WORKFLOW_ACTION_OPTIONS) + // Remote OCR is absent until the workflow has a consumption trigger + expect(component.actionTypeOptions).toEqual( + WORKFLOW_ACTION_OPTIONS.filter( + (a) => a.id !== WorkflowActionType.RemoteOcr + ) + ) expect( component.getActionTypeOptionName(WorkflowActionType.Assignment) ).toEqual('Assignment') @@ -237,7 +243,78 @@ describe('WorkflowEditDialogComponent', () => { jest.spyOn(settingsService, 'get').mockReturnValue(false) component.ngOnInit() expect(component.actionTypeOptions).toEqual( - WORKFLOW_ACTION_OPTIONS.filter((a) => a.id !== WorkflowActionType.Email) + WORKFLOW_ACTION_OPTIONS.filter( + (a) => + a.id !== WorkflowActionType.Email && + a.id !== WorkflowActionType.RemoteOcr + ) + ) + }) + + it('should offer remote OCR only for consumption workflows', () => { + jest.spyOn(settingsService, 'get').mockReturnValue(true) + + // A consumption trigger makes the action reachable + component.object = { + name: 'Workflow 1', + order: 0, + enabled: true, + triggers: [{ type: WorkflowTriggerType.Consumption }], + actions: [], + } as Workflow + component.ngOnInit() + expect(component.actionTypeOptions.map((a) => a.id)).toContain( + WorkflowActionType.RemoteOcr + ) + + // Any other trigger type runs after the document has been parsed + component.object = { + name: 'Workflow 2', + order: 0, + enabled: true, + triggers: [{ type: WorkflowTriggerType.DocumentAdded }], + actions: [], + } as Workflow + component.ngOnInit() + expect(component.actionTypeOptions.map((a) => a.id)).not.toContain( + WorkflowActionType.RemoteOcr + ) + }) + + it('should keep remote OCR listed when an action already uses it', () => { + jest.spyOn(settingsService, 'get').mockReturnValue(true) + + // Otherwise changing the trigger would silently blank the selection + component.object = { + name: 'Workflow 1', + order: 0, + enabled: true, + triggers: [{ type: WorkflowTriggerType.DocumentAdded }], + actions: [{ type: WorkflowActionType.RemoteOcr }], + } as Workflow + component.ngOnInit() + + expect(component.actionTypeOptions.map((a) => a.id)).toContain( + WorkflowActionType.RemoteOcr + ) + }) + + it('should not offer remote OCR when no engine is configured', () => { + jest + .spyOn(settingsService, 'get') + .mockImplementation((key) => key !== SETTINGS_KEYS.REMOTE_OCR_CONFIGURED) + + component.object = { + name: 'Workflow 1', + order: 0, + enabled: true, + triggers: [{ type: WorkflowTriggerType.Consumption }], + actions: [], + } as Workflow + component.ngOnInit() + + expect(component.actionTypeOptions.map((a) => a.id)).not.toContain( + WorkflowActionType.RemoteOcr ) }) diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts index 8e8dd6ef7..dad74c88b 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts @@ -148,6 +148,10 @@ export const WORKFLOW_ACTION_OPTIONS = [ id: WorkflowActionType.MoveToTrash, name: $localize`Move to trash`, }, + { + id: WorkflowActionType.RemoteOcr, + name: $localize`Remote OCR`, + }, ] export enum TriggerFilterType { @@ -544,17 +548,36 @@ export class WorkflowEditDialogComponent ngOnInit(): void { super.ngOnInit() this.updateAllTriggerActionFields() - this.objectForm.valueChanges.subscribe( - this.checkRemovalActionFields.bind(this) - ) + this.objectForm.valueChanges.subscribe((formWorkflow) => { + this.checkRemovalActionFields(formWorkflow) + this.updateAllowedActionTypes(formWorkflow) + }) this.checkRemovalActionFields(this.objectForm.value) - this.allowedActionTypes.set( - this.settingsService.get(SETTINGS_KEYS.EMAIL_ENABLED) - ? WORKFLOW_ACTION_OPTIONS - : WORKFLOW_ACTION_OPTIONS.filter( - (a) => a.id !== WorkflowActionType.Email - ) - ) + this.updateAllowedActionTypes(this.objectForm.value) + } + + private updateAllowedActionTypes(formWorkflow: Workflow) { + let allowed = WORKFLOW_ACTION_OPTIONS + + if (!this.settingsService.get(SETTINGS_KEYS.EMAIL_ENABLED)) { + allowed = allowed.filter((a) => a.id !== WorkflowActionType.Email) + } + + // Remote OCR is decided before the document is parsed, so it is only + // offered for workflows that run at consumption. + const remoteOcrUsable = + this.settingsService.get(SETTINGS_KEYS.REMOTE_OCR_CONFIGURED) && + (formWorkflow?.triggers?.some( + (trigger) => trigger.type === WorkflowTriggerType.Consumption + ) || + formWorkflow?.actions?.some( + (action) => action.type === WorkflowActionType.RemoteOcr + )) + if (!remoteOcrUsable) { + allowed = allowed.filter((a) => a.id !== WorkflowActionType.RemoteOcr) + } + + this.allowedActionTypes.set(allowed) } private checkRemovalActionFields(formWorkflow: Workflow) { diff --git a/src-ui/src/app/data/workflow-action.ts b/src-ui/src/app/data/workflow-action.ts index 5ddaeba7e..09ef5418f 100644 --- a/src-ui/src/app/data/workflow-action.ts +++ b/src-ui/src/app/data/workflow-action.ts @@ -7,6 +7,7 @@ export enum WorkflowActionType { Webhook = 4, PasswordRemoval = 5, MoveToTrash = 6, + RemoteOcr = 7, } export interface WorkflowActionEmail extends ObjectWithId {