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 {