1 <form [formGroup]="objectForm" (ngSubmit)="save()" autocomplete="off">
2 <div class="modal-header">
3 <h4 class="modal-title" id="modal-basic-title">{{getTitle()}}</h4>
5 <span class="badge bg-primary text-primary-text-contrast ms-2">ID: {{object.id}}</span>
7 <button type="button" [disabled]="!closeEnabled" class="btn-close" aria-label="Close" (click)="cancel()">
10 <div class="modal-body">
12 <div class="col-md-6">
13 <pngx-input-text i18n-title title="Name" formControlName="name" [error]="error?.name" autocomplete="off"></pngx-input-text>
16 <pngx-input-number i18n-title title="Sort order" formControlName="order" [showAdd]="false" [error]="error?.order"></pngx-input-number>
19 <pngx-input-switch i18n-title title="Enabled" formControlName="enabled" [error]="error?.enabled"></pngx-input-switch>
23 <div ngbAccordionItem>
24 <h2 ngbAccordionHeader>
25 <button ngbAccordionButton i18n>Triggers</button>
27 <div ngbAccordionCollapse>
28 <div ngbAccordionBody>
31 <p class="p-2" i18n>Trigger Workflow On:</p>
32 <button type="button" class="btn btn-sm btn-outline-primary ms-auto mb-3" (click)="addTrigger()">
33 <i-bs name="plus-circle"></i-bs> <ng-container i18n>Add Trigger</ng-container>
36 <div ngbAccordion [closeOthers]="true">
37 @for (trigger of object?.triggers; track trigger; let i = $index){
38 <div ngbAccordionItem>
39 <div ngbAccordionHeader>
40 <button ngbAccordionButton>{{i + 1}}. {{getTriggerTypeOptionName(triggerFields.controls[i].value.type)}}
42 <span class="badge bg-primary text-primary-text-contrast ms-2">ID: {{trigger.id}}</span>
47 (confirm)="removeTrigger(i)"
48 buttonClasses="btn-link text-danger ms-2"
50 </pngx-confirm-button>
53 <div ngbAccordionCollapse>
54 <div ngbAccordionBody>
55 <ng-template [ngTemplateOutlet]="triggerForm" [ngTemplateOutletContext]="{ formGroup: triggerFields.controls[i], trigger: trigger }"></ng-template>
65 <div ngbAccordionItem>
66 <h2 ngbAccordionHeader>
67 <button class="btn-lg" ngbAccordionButton i18n>Actions</button>
69 <div ngbAccordionCollapse>
70 <div ngbAccordionBody>
73 <p class="p-2" i18n>Apply Actions:</p>
74 <button type="button" class="btn btn-sm btn-outline-primary ms-auto mb-3" (click)="addAction()">
75 <i-bs name="plus-circle"></i-bs> <ng-container i18n>Add Action</ng-container>
78 <div ngbAccordion [closeOthers]="true" cdkDropList (cdkDropListDropped)="onActionDrop($event)">
79 @for (action of object?.actions; track action; let i = $index){
80 <div ngbAccordionItem cdkDrag [formGroup]="actionFields.controls[i]">
81 <div ngbAccordionHeader>
82 <button ngbAccordionButton>{{i + 1}}. {{getActionTypeOptionName(actionFields.controls[i].value.type)}}
84 <span class="badge bg-primary text-primary-text-contrast ms-2">ID: {{action.id}}</span>
89 (confirm)="removeAction(i)"
90 buttonClasses="btn-link text-danger ms-2"
92 </pngx-confirm-button>
95 <div ngbAccordionCollapse>
96 <div ngbAccordionBody>
97 <ng-template [ngTemplateOutlet]="actionForm" [ngTemplateOutletContext]="{ formGroup: actionFields.controls[i], action: action }"></ng-template>
109 <div class="modal-footer">
110 @if (error?.non_field_errors) {
111 <span class="text-danger"><ng-container i18n>Error</ng-container>: {{error.non_field_errors}}</span>
113 <button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button>
114 <button type="submit" class="btn btn-primary" i18n [disabled]="networkActive">Save</button>
118 <ng-template #triggerForm let-formGroup="formGroup" let-trigger="trigger">
119 <div [formGroup]="formGroup">
120 <input type="hidden" formControlName="id" />
121 <pngx-input-select i18n-title title="Trigger type" [horizontal]="true" [items]="triggerTypeOptions" formControlName="type"></pngx-input-select>
122 @if (formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
123 <p class="small" i18n>Set scheduled trigger offset and which date field to use.</p>
126 <pngx-input-number i18n-title title="Offset days" formControlName="schedule_offset_days" [showAdd]="false" [error]="error?.schedule_offset_days"></pngx-input-number>
129 <pngx-input-select i18n-title title="Relative to" formControlName="schedule_date_field" [items]="scheduleDateFieldOptions" [error]="error?.schedule_date_field"></pngx-input-select>
131 @if (formGroup.get('schedule_date_field').value === 'custom_field') {
133 <pngx-input-select i18n-title title="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>
139 <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>
142 @if (formGroup.get('schedule_is_recurring').value === true) {
143 <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>
148 <p class="small" i18n>Trigger for documents that match <em>all</em> filters specified below.</p>
151 <pngx-input-text i18n-title title="Filter filename" formControlName="filter_filename" i18n-hint hint="Apply to documents that match this filename. Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." [error]="error?.filter_filename"></pngx-input-text>
152 @if (formGroup.get('type').value === WorkflowTriggerType.Consumption) {
153 <pngx-input-select i18n-title title="Filter sources" [items]="sourceOptions" [multiple]="true" formControlName="sources" [error]="error?.sources"></pngx-input-select>
154 <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>
155 <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>
157 @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
158 <pngx-input-select i18n-title title="Content matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
159 @if (patternRequired) {
160 <pngx-input-text i18n-title title="Content matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
162 @if (patternRequired) {
163 <pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
167 @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
168 <div class="col-md-6">
169 <pngx-input-tags [allowCreate]="false" i18n-title title="Has any of tags" formControlName="filter_has_tags"></pngx-input-tags>
170 <pngx-input-select i18n-title title="Has correspondent" [items]="correspondents" [allowNull]="true" formControlName="filter_has_correspondent"></pngx-input-select>
171 <pngx-input-select i18n-title title="Has document type" [items]="documentTypes" [allowNull]="true" formControlName="filter_has_document_type"></pngx-input-select>
178 <ng-template #actionForm let-formGroup="formGroup" let action="action">
179 <div [formGroup]="formGroup">
180 <input type="hidden" formControlName="id" />
181 <pngx-input-select i18n-title title="Action type" [horizontal]="true" [items]="actionTypeOptions" formControlName="type"></pngx-input-select>
182 @switch(formGroup.get('type').value) {
183 @case ( WorkflowActionType.Assignment) {
186 <pngx-input-text i18n-title title="Assign title" formControlName="assign_title" i18n-hint hint="Can include some placeholders, see <a target='_blank' href='https://docs.paperless-ngx.com/usage/#workflows'>documentation</a>." [error]="error?.actions?.[i]?.assign_title"></pngx-input-text>
187 <pngx-input-tags [allowCreate]="false" i18n-title title="Assign tags" formControlName="assign_tags"></pngx-input-tags>
188 <pngx-input-select i18n-title title="Assign document type" [items]="documentTypes" [allowNull]="true" formControlName="assign_document_type"></pngx-input-select>
189 <pngx-input-select i18n-title title="Assign correspondent" [items]="correspondents" [allowNull]="true" formControlName="assign_correspondent"></pngx-input-select>
190 <pngx-input-select i18n-title title="Assign storage path" [items]="storagePaths" [allowNull]="true" formControlName="assign_storage_path"></pngx-input-select>
191 <pngx-input-select i18n-title title="Assign custom fields" multiple="true" [items]="customFields" [allowNull]="true" formControlName="assign_custom_fields"></pngx-input-select>
194 <pngx-input-select i18n-title title="Assign owner" [items]="users" bindLabel="username" formControlName="assign_owner" [allowNull]="true"></pngx-input-select>
196 <label class="form-label" i18n>Assign view permissions</label>
198 <div class="row mb-1">
199 <div class="col-lg-3">
200 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
202 <div class="col-lg-9">
203 <pngx-permissions-user type="view" formControlName="assign_view_users"></pngx-permissions-user>
207 <div class="col-lg-3">
208 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
210 <div class="col-lg-9">
211 <pngx-permissions-group type="view" formControlName="assign_view_groups"></pngx-permissions-group>
215 <label class="form-label" i18n>Assign edit permissions</label>
217 <div class="row mb-1">
218 <div class="col-lg-3">
219 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
221 <div class="col-lg-9">
222 <pngx-permissions-user type="change" formControlName="assign_change_users"></pngx-permissions-user>
226 <div class="col-lg-3">
227 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
229 <div class="col-lg-9">
230 <pngx-permissions-group type="change" formControlName="assign_change_groups"></pngx-permissions-group>
233 <small class="form-text text-muted text-end d-block" i18n>Edit permissions also grant viewing permissions</small>
239 @case (WorkflowActionType.Removal) {
242 <h6 class="form-label" i18n>Remove tags</h6>
243 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_tags"></pngx-input-switch>
245 <pngx-input-tags [allowCreate]="false" title="" formControlName="remove_tags"></pngx-input-tags>
248 <h6 class="form-label" i18n>Remove correspondents</h6>
249 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_correspondents"></pngx-input-switch>
251 <pngx-input-select i18n-title title="" multiple="true" [items]="correspondents" formControlName="remove_correspondents"></pngx-input-select>
254 <h6 class="form-label" i18n>Remove document types</h6>
255 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_document_types"></pngx-input-switch>
257 <pngx-input-select i18n-title title="" multiple="true" [items]="documentTypes" formControlName="remove_document_types"></pngx-input-select>
260 <h6 class="form-label" i18n>Remove storage paths</h6>
261 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_storage_paths"></pngx-input-switch>
263 <pngx-input-select i18n-title title="" multiple="true" [items]="storagePaths" formControlName="remove_storage_paths"></pngx-input-select>
266 <h6 class="form-label" i18n>Remove custom fields</h6>
267 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_custom_fields"></pngx-input-switch>
269 <pngx-input-select i18n-title title="" multiple="true" [items]="customFields" formControlName="remove_custom_fields"></pngx-input-select>
273 <h6 class="form-label" i18n>Remove owners</h6>
274 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_owners"></pngx-input-switch>
276 <pngx-input-select i18n-title title="" multiple="true" [items]="users" bindLabel="username" formControlName="remove_owners"></pngx-input-select>
279 <h6 class="form-label" i18n>Remove permissions</h6>
280 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_permissions"></pngx-input-switch>
282 <label class="form-label" i18n>View permissions</label>
284 <div class="row mb-1">
285 <div class="col-lg-3">
286 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
288 <div class="col-lg-9">
289 <pngx-permissions-user type="view" formControlName="remove_view_users"></pngx-permissions-user>
293 <div class="col-lg-3">
294 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
296 <div class="col-lg-9">
297 <pngx-permissions-group type="view" formControlName="remove_view_groups"></pngx-permissions-group>
301 <label class="form-label" i18n>Edit permissions</label>
303 <div class="row mb-1">
304 <div class="col-lg-3">
305 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
307 <div class="col-lg-9">
308 <pngx-permissions-user type="change" formControlName="remove_change_users"></pngx-permissions-user>
312 <div class="col-lg-3">
313 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
315 <div class="col-lg-9">
316 <pngx-permissions-group type="change" formControlName="remove_change_groups"></pngx-permissions-group>
319 <small class="form-text text-muted text-end d-block" i18n>Edit permissions also grant viewing permissions</small>
325 @case (WorkflowActionType.Email) {
326 <div class="row" [formGroup]="formGroup.get('email')">
327 <input type="hidden" formControlName="id" />
329 <pngx-input-text i18n-title title="Email subject" formControlName="subject" [error]="error?.actions?.[i]?.email?.subject"></pngx-input-text>
330 <pngx-input-textarea i18n-title title="Email body" formControlName="body" [error]="error?.actions?.[i]?.email?.body"></pngx-input-textarea>
331 <pngx-input-text i18n-title title="Email recipients" formControlName="to" [error]="error?.actions?.[i]?.email?.to"></pngx-input-text>
332 <pngx-input-switch i18n-title title="Attach document" formControlName="include_document"></pngx-input-switch>
336 @case (WorkflowActionType.Webhook) {
337 <div class="row" [formGroup]="formGroup.get('webhook')">
338 <input type="hidden" formControlName="id" />
340 <pngx-input-text i18n-title title="Webhook url" formControlName="url" [error]="error?.actions?.[i]?.url"></pngx-input-text>
341 <pngx-input-switch i18n-title title="Use parameters for webhook body" formControlName="use_params"></pngx-input-switch>
342 @if (formGroup.get('webhook').value['use_params']) {
343 <pngx-input-entries i18n-title title="Webhook params" formControlName="params" [error]="error?.actions?.[i]?.params"></pngx-input-entries>
345 <pngx-input-textarea i18n-title title="Webhook body" formControlName="body" [error]="error?.actions?.[i]?.body"></pngx-input-textarea>
347 <pngx-input-entries i18n-title title="Webhook headers" formControlName="headers" [error]="error?.actions?.[i]?.headers"></pngx-input-entries>
348 <pngx-input-switch i18n-title title="Include document" formControlName="include_document"></pngx-input-switch>