mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Feature: scheduled workflow trigger (#8036)
This commit is contained in:
@@ -119,6 +119,32 @@
|
||||
<div [formGroup]="formGroup">
|
||||
<input type="hidden" formControlName="id" />
|
||||
<pngx-input-select i18n-title title="Trigger type" [horizontal]="true" [items]="triggerTypeOptions" formControlName="type"></pngx-input-select>
|
||||
@if (formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
|
||||
<p class="small" i18n>Set scheduled trigger offset and which field to use.</p>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<pngx-input-number i18n-title title="Offset days" formControlName="schedule_offset_days" i18n-hint hint="Use 0 for immediate." [showAdd]="false" [error]="error?.schedule_offset_days"></pngx-input-number>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<pngx-input-select i18n-title title="Relative to" formControlName="schedule_date_field" [items]="scheduleDateFieldOptions" [error]="error?.schedule_date_field"></pngx-input-select>
|
||||
</div>
|
||||
@if (formGroup.get('schedule_date_field').value === 'custom_field') {
|
||||
<div class="col-4">
|
||||
<pngx-input-select i18n-title title="Delay custom field" formControlName="schedule_date_custom_field" [items]="dateCustomFields" i18n-hint hint="Custom field to use for date." [error]="error?.schedule_date_custom_field"></pngx-input-select>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<pngx-input-check i18n-title title="Recurring" formControlName="schedule_is_recurring" i18n-hint hint="Trigger is recurring." [error]="error?.schedule_is_recurring"></pngx-input-check>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
@if (formGroup.get('schedule_is_recurring').value === true) {
|
||||
<pngx-input-number i18n-title title="Recurring interval days" formControlName="schedule_recurring_interval_days" i18n-hint hint="Repeat the trigger every n days." [showAdd]="false" [error]="error?.schedule_recurring_interval_days"></pngx-input-number>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<p class="small" i18n>Trigger for documents that match <em>all</em> filters specified below.</p>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@@ -128,7 +154,7 @@
|
||||
<pngx-input-text i18n-title title="Filter path" formControlName="filter_path" i18n-hint hint="Apply to documents that match this path. Wildcards specified as * are allowed. Case-normalized.</a>" [error]="error?.filter_path"></pngx-input-text>
|
||||
<pngx-input-select i18n-title title="Filter mail rule" [items]="mailRules" [allowNull]="true" formControlName="filter_mailrule" i18n-hint hint="Apply to documents consumed via this mail rule." [error]="error?.filter_mailrule"></pngx-input-select>
|
||||
}
|
||||
@if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated) {
|
||||
@if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
|
||||
<pngx-input-select i18n-title title="Content matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
|
||||
@if (patternRequired) {
|
||||
<pngx-input-text i18n-title title="Content matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
|
||||
@@ -138,7 +164,7 @@
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated) {
|
||||
@if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
|
||||
<div class="col-md-6">
|
||||
<pngx-input-tags [allowCreate]="false" i18n-title title="Has any of tags" formControlName="filter_has_tags"></pngx-input-tags>
|
||||
<pngx-input-select i18n-title title="Has correspondent" [items]="correspondents" [allowNull]="true" formControlName="filter_has_correspondent"></pngx-input-select>
|
||||
|
@@ -22,6 +22,7 @@ import { SwitchComponent } from '../../input/switch/switch.component'
|
||||
import { EditDialogMode } from '../edit-dialog.component'
|
||||
import {
|
||||
DOCUMENT_SOURCE_OPTIONS,
|
||||
SCHEDULE_DATE_FIELD_OPTIONS,
|
||||
WORKFLOW_ACTION_OPTIONS,
|
||||
WORKFLOW_TYPE_OPTIONS,
|
||||
WorkflowEditDialogComponent,
|
||||
@@ -40,6 +41,7 @@ import {
|
||||
import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'
|
||||
import { ConfirmButtonComponent } from '../../confirm-button/confirm-button.component'
|
||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
||||
import { CustomFieldDataType } from 'src/app/data/custom-field'
|
||||
|
||||
const workflow: Workflow = {
|
||||
name: 'Workflow 1',
|
||||
@@ -148,7 +150,18 @@ describe('WorkflowEditDialogComponent', () => {
|
||||
useValue: {
|
||||
listAll: () =>
|
||||
of({
|
||||
results: [],
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'cf1',
|
||||
data_type: CustomFieldDataType.String,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'cf2',
|
||||
data_type: CustomFieldDataType.Date,
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
},
|
||||
@@ -186,7 +199,7 @@ describe('WorkflowEditDialogComponent', () => {
|
||||
expect(editTitleSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return source options, type options, type name', () => {
|
||||
it('should return source options, type options, type name, schedule date field options', () => {
|
||||
// coverage
|
||||
expect(component.sourceOptions).toEqual(DOCUMENT_SOURCE_OPTIONS)
|
||||
expect(component.triggerTypeOptions).toEqual(WORKFLOW_TYPE_OPTIONS)
|
||||
@@ -200,6 +213,9 @@ describe('WorkflowEditDialogComponent', () => {
|
||||
component.getActionTypeOptionName(WorkflowActionType.Assignment)
|
||||
).toEqual('Assignment')
|
||||
expect(component.getActionTypeOptionName(null)).toEqual('')
|
||||
expect(component.scheduleDateFieldOptions).toEqual(
|
||||
SCHEDULE_DATE_FIELD_OPTIONS
|
||||
)
|
||||
})
|
||||
|
||||
it('should support add and remove triggers and actions', () => {
|
||||
|
@@ -16,9 +16,10 @@ import { EditDialogComponent } from '../edit-dialog.component'
|
||||
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
|
||||
import { MailRule } from 'src/app/data/mail-rule'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { CustomField } from 'src/app/data/custom-field'
|
||||
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
|
||||
import {
|
||||
DocumentSource,
|
||||
ScheduleDateField,
|
||||
WorkflowTrigger,
|
||||
WorkflowTriggerType,
|
||||
} from 'src/app/data/workflow-trigger'
|
||||
@@ -48,6 +49,25 @@ export const DOCUMENT_SOURCE_OPTIONS = [
|
||||
},
|
||||
]
|
||||
|
||||
export const SCHEDULE_DATE_FIELD_OPTIONS = [
|
||||
{
|
||||
id: ScheduleDateField.Added,
|
||||
name: $localize`Added`,
|
||||
},
|
||||
{
|
||||
id: ScheduleDateField.Created,
|
||||
name: $localize`Created`,
|
||||
},
|
||||
{
|
||||
id: ScheduleDateField.Modified,
|
||||
name: $localize`Modified`,
|
||||
},
|
||||
{
|
||||
id: ScheduleDateField.CustomField,
|
||||
name: $localize`Custom Field`,
|
||||
},
|
||||
]
|
||||
|
||||
export const WORKFLOW_TYPE_OPTIONS = [
|
||||
{
|
||||
id: WorkflowTriggerType.Consumption,
|
||||
@@ -61,6 +81,10 @@ export const WORKFLOW_TYPE_OPTIONS = [
|
||||
id: WorkflowTriggerType.DocumentUpdated,
|
||||
name: $localize`Document Updated`,
|
||||
},
|
||||
{
|
||||
id: WorkflowTriggerType.Scheduled,
|
||||
name: $localize`Scheduled`,
|
||||
},
|
||||
]
|
||||
|
||||
export const WORKFLOW_ACTION_OPTIONS = [
|
||||
@@ -96,6 +120,7 @@ export class WorkflowEditDialogComponent
|
||||
storagePaths: StoragePath[]
|
||||
mailRules: MailRule[]
|
||||
customFields: CustomField[]
|
||||
dateCustomFields: CustomField[]
|
||||
|
||||
expandedItem: number = null
|
||||
|
||||
@@ -135,7 +160,12 @@ export class WorkflowEditDialogComponent
|
||||
customFieldsService
|
||||
.listAll()
|
||||
.pipe(first())
|
||||
.subscribe((result) => (this.customFields = result.results))
|
||||
.subscribe((result) => {
|
||||
this.customFields = result.results
|
||||
this.dateCustomFields = this.customFields?.filter(
|
||||
(f) => f.data_type === CustomFieldDataType.Date
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
getCreateTitle() {
|
||||
@@ -314,6 +344,15 @@ export class WorkflowEditDialogComponent
|
||||
filter_has_document_type: new FormControl(
|
||||
trigger.filter_has_document_type
|
||||
),
|
||||
schedule_offset_days: new FormControl(trigger.schedule_offset_days),
|
||||
schedule_is_recurring: new FormControl(trigger.schedule_is_recurring),
|
||||
schedule_recurring_interval_days: new FormControl(
|
||||
trigger.schedule_recurring_interval_days
|
||||
),
|
||||
schedule_date_field: new FormControl(trigger.schedule_date_field),
|
||||
schedule_date_custom_field: new FormControl(
|
||||
trigger.schedule_date_custom_field
|
||||
),
|
||||
}),
|
||||
{ emitEvent }
|
||||
)
|
||||
@@ -388,6 +427,10 @@ export class WorkflowEditDialogComponent
|
||||
return WORKFLOW_TYPE_OPTIONS
|
||||
}
|
||||
|
||||
get scheduleDateFieldOptions() {
|
||||
return SCHEDULE_DATE_FIELD_OPTIONS
|
||||
}
|
||||
|
||||
getTriggerTypeOptionName(type: WorkflowTriggerType): string {
|
||||
return this.triggerTypeOptions.find((t) => t.id === type)?.name ?? ''
|
||||
}
|
||||
@@ -408,6 +451,11 @@ export class WorkflowEditDialogComponent
|
||||
matching_algorithm: MATCH_NONE,
|
||||
match: '',
|
||||
is_insensitive: true,
|
||||
schedule_offset_days: 0,
|
||||
schedule_is_recurring: false,
|
||||
schedule_recurring_interval_days: 1,
|
||||
schedule_date_field: ScheduleDateField.Added,
|
||||
schedule_date_custom_field: null,
|
||||
}
|
||||
this.object.triggers.push(trigger)
|
||||
this.createTriggerField(trigger)
|
||||
|
Reference in New Issue
Block a user