]> git.ipfire.org Git - thirdparty/paperless-ngx.git/blob
7163ba289ead5f346072dd72588684ff3f061a9e
[thirdparty/paperless-ngx.git] /
1 <form [formGroup]="objectForm" (ngSubmit)="save()" autocomplete="off">
2 <div class="modal-header">
3 <h4 class="modal-title" id="modal-basic-title">{{getTitle()}}</h4>
4 @if (object?.id) {
5 <span class="badge bg-primary text-primary-text-contrast ms-2">ID: {{object.id}}</span>
6 }
7 <button type="button" [disabled]="!closeEnabled" class="btn-close" aria-label="Close" (click)="cancel()">
8 </button>
9 </div>
10 <div class="modal-body">
11 <div class="row">
12 <div class="col-md-6">
13 <pngx-input-text i18n-title title="Name" formControlName="name" [error]="error?.name" autocomplete="off"></pngx-input-text>
14 </div>
15 <div class="col-4">
16 <pngx-input-number i18n-title title="Sort order" formControlName="order" [showAdd]="false" [error]="error?.order"></pngx-input-number>
17 </div>
18 <div class="col">
19 <pngx-input-switch i18n-title title="Enabled" formControlName="enabled" [error]="error?.enabled"></pngx-input-switch>
20 </div>
21 </div>
22 <div ngbAccordion>
23 <div ngbAccordionItem>
24 <h2 ngbAccordionHeader>
25 <button ngbAccordionButton i18n>Triggers</button>
26 </h2>
27 <div ngbAccordionCollapse>
28 <div ngbAccordionBody>
29 <ng-template>
30 <div class="d-flex">
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>&nbsp;<ng-container i18n>Add Trigger</ng-container>
34 </button>
35 </div>
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)}}
41 @if(trigger.id) {
42 <span class="badge bg-primary text-primary-text-contrast ms-2">ID: {{trigger.id}}</span>
43 }
44 <pngx-confirm-button
45 label="Delete"
46 i18n-label
47 (confirm)="removeTrigger(i)"
48 buttonClasses="btn-link text-danger ms-2"
49 iconName="trash">
50 </pngx-confirm-button>
51 </button>
52 </div>
53 <div ngbAccordionCollapse>
54 <div ngbAccordionBody>
55 <ng-template [ngTemplateOutlet]="triggerForm" [ngTemplateOutletContext]="{ formGroup: triggerFields.controls[i], trigger: trigger }"></ng-template>
56 </div>
57 </div>
58 </div>
59 }
60 </div>
61 </ng-template>
62 </div>
63 </div>
64 </div>
65 <div ngbAccordionItem>
66 <h2 ngbAccordionHeader>
67 <button class="btn-lg" ngbAccordionButton i18n>Actions</button>
68 </h2>
69 <div ngbAccordionCollapse>
70 <div ngbAccordionBody>
71 <ng-template>
72 <div class="d-flex">
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>&nbsp;<ng-container i18n>Add Action</ng-container>
76 </button>
77 </div>
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)}}
83 @if(action.id) {
84 <span class="badge bg-primary text-primary-text-contrast ms-2">ID: {{action.id}}</span>
85 }
86 <pngx-confirm-button
87 label="Delete"
88 i18n-label
89 (confirm)="removeAction(i)"
90 buttonClasses="btn-link text-danger ms-2"
91 iconName="trash">
92 </pngx-confirm-button>
93 </button>
94 </div>
95 <div ngbAccordionCollapse>
96 <div ngbAccordionBody>
97 <ng-template [ngTemplateOutlet]="actionForm" [ngTemplateOutletContext]="{ formGroup: actionFields.controls[i], action: action }"></ng-template>
98 </div>
99 </div>
100 </div>
101 }
102 </div>
103 </ng-template>
104 </div>
105 </div>
106 </div>
107 </div>
108 </div>
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>
112 }
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>
115 </div>
116 </form>
117
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>
124 <div class="row">
125 <div class="col-4">
126 <pngx-input-number
127 i18n-title
128 title="Offset days"
129 formControlName="schedule_offset_days"
130 [showAdd]="false"
131 [error]="error?.schedule_offset_days"
132 hint="Positive values will trigger after the date, negative values before."
133 i18n-hint
134 ></pngx-input-number>
135 </div>
136 <div class="col-4">
137 <pngx-input-select i18n-title title="Relative to" formControlName="schedule_date_field" [items]="scheduleDateFieldOptions" [error]="error?.schedule_date_field"></pngx-input-select>
138 </div>
139 @if (formGroup.get('schedule_date_field').value === 'custom_field') {
140 <div class="col-4">
141 <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>
142 </div>
143 }
144 </div>
145 <div class="row">
146 <div class="col-4">
147 <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>
148 </div>
149 <div class="col-4">
150 @if (formGroup.get('schedule_is_recurring').value === true) {
151 <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>
152 }
153 </div>
154 </div>
155 }
156 <p class="small" i18n>Trigger for documents that match <em>all</em> filters specified below.</p>
157 <div class="row">
158 <div class="col">
159 <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>
160 @if (formGroup.get('type').value === WorkflowTriggerType.Consumption) {
161 <pngx-input-select i18n-title title="Filter sources" [items]="sourceOptions" [multiple]="true" formControlName="sources" [error]="error?.sources"></pngx-input-select>
162 <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>
163 <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>
164 }
165 @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
166 <pngx-input-select i18n-title title="Content matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></pngx-input-select>
167 @if (patternRequired) {
168 <pngx-input-text i18n-title title="Content matching pattern" formControlName="match" [error]="error?.match"></pngx-input-text>
169 }
170 @if (patternRequired) {
171 <pngx-input-check i18n-title title="Case insensitive" formControlName="is_insensitive"></pngx-input-check>
172 }
173 }
174 </div>
175 @if (formGroup.get('type').value === WorkflowTriggerType.DocumentAdded || formGroup.get('type').value === WorkflowTriggerType.DocumentUpdated || formGroup.get('type').value === WorkflowTriggerType.Scheduled) {
176 <div class="col-md-6">
177 <pngx-input-tags [allowCreate]="false" i18n-title title="Has any of tags" formControlName="filter_has_tags"></pngx-input-tags>
178 <pngx-input-select i18n-title title="Has correspondent" [items]="correspondents" [allowNull]="true" formControlName="filter_has_correspondent"></pngx-input-select>
179 <pngx-input-select i18n-title title="Has document type" [items]="documentTypes" [allowNull]="true" formControlName="filter_has_document_type"></pngx-input-select>
180 <pngx-input-select i18n-title title="Has storage path" [items]="storagePaths" [allowNull]="true" formControlName="filter_has_storage_path"></pngx-input-select>
181 </div>
182 }
183 </div>
184 </div>
185 </ng-template>
186
187 <ng-template #actionForm let-formGroup="formGroup" let action="action">
188 <div [formGroup]="formGroup">
189 <input type="hidden" formControlName="id" />
190 <pngx-input-select i18n-title title="Action type" [horizontal]="true" [items]="actionTypeOptions" formControlName="type"></pngx-input-select>
191 @switch(formGroup.get('type').value) {
192 @case (WorkflowActionType.Assignment) {
193 <div class="row">
194 <div class="col">
195 <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>
196 <pngx-input-tags [allowCreate]="false" i18n-title title="Assign tags" formControlName="assign_tags"></pngx-input-tags>
197 <pngx-input-select i18n-title title="Assign document type" [items]="documentTypes" [allowNull]="true" formControlName="assign_document_type"></pngx-input-select>
198 <pngx-input-select i18n-title title="Assign correspondent" [items]="correspondents" [allowNull]="true" formControlName="assign_correspondent"></pngx-input-select>
199 <pngx-input-select i18n-title title="Assign storage path" [items]="storagePaths" [allowNull]="true" formControlName="assign_storage_path"></pngx-input-select>
200 <pngx-input-select i18n-title title="Assign custom fields" multiple="true" [items]="customFields" [allowNull]="true" formControlName="assign_custom_fields"></pngx-input-select>
201 <pngx-input-custom-fields-values formControlName="assign_custom_fields_values" [selectedFields]="formGroup.get('assign_custom_fields').value" (removeSelectedField)="removeSelectedCustomField($event, formGroup)"></pngx-input-custom-fields-values>
202 </div>
203 <div class="col">
204 <pngx-input-select i18n-title title="Assign owner" [items]="users" bindLabel="username" formControlName="assign_owner" [allowNull]="true"></pngx-input-select>
205 <div>
206 <label class="form-label" i18n>Assign view permissions</label>
207 <div class="mb-2">
208 <div class="row mb-1">
209 <div class="col-lg-3">
210 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
211 </div>
212 <div class="col-lg-9">
213 <pngx-permissions-user type="view" formControlName="assign_view_users"></pngx-permissions-user>
214 </div>
215 </div>
216 <div class="row">
217 <div class="col-lg-3">
218 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
219 </div>
220 <div class="col-lg-9">
221 <pngx-permissions-group type="view" formControlName="assign_view_groups"></pngx-permissions-group>
222 </div>
223 </div>
224 </div>
225 <label class="form-label" i18n>Assign edit permissions</label>
226 <div>
227 <div class="row mb-1">
228 <div class="col-lg-3">
229 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
230 </div>
231 <div class="col-lg-9">
232 <pngx-permissions-user type="change" formControlName="assign_change_users"></pngx-permissions-user>
233 </div>
234 </div>
235 <div class="row">
236 <div class="col-lg-3">
237 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
238 </div>
239 <div class="col-lg-9">
240 <pngx-permissions-group type="change" formControlName="assign_change_groups"></pngx-permissions-group>
241 </div>
242 </div>
243 <small class="form-text text-muted text-end d-block" i18n>Edit permissions also grant viewing permissions</small>
244 </div>
245 </div>
246 </div>
247 </div>
248 }
249 @case (WorkflowActionType.Removal) {
250 <div class="row">
251 <div class="col">
252 <h6 class="form-label" i18n>Remove tags</h6>
253 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_tags"></pngx-input-switch>
254 <div class="mt-n3">
255 <pngx-input-tags [allowCreate]="false" title="" formControlName="remove_tags"></pngx-input-tags>
256 </div>
257
258 <h6 class="form-label" i18n>Remove correspondents</h6>
259 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_correspondents"></pngx-input-switch>
260 <div class="mt-n3">
261 <pngx-input-select i18n-title title="" multiple="true" [items]="correspondents" formControlName="remove_correspondents"></pngx-input-select>
262 </div>
263
264 <h6 class="form-label" i18n>Remove document types</h6>
265 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_document_types"></pngx-input-switch>
266 <div class="mt-n3">
267 <pngx-input-select i18n-title title="" multiple="true" [items]="documentTypes" formControlName="remove_document_types"></pngx-input-select>
268 </div>
269
270 <h6 class="form-label" i18n>Remove storage paths</h6>
271 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_storage_paths"></pngx-input-switch>
272 <div class="mt-n3">
273 <pngx-input-select i18n-title title="" multiple="true" [items]="storagePaths" formControlName="remove_storage_paths"></pngx-input-select>
274 </div>
275
276 <h6 class="form-label" i18n>Remove custom fields</h6>
277 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_custom_fields"></pngx-input-switch>
278 <div class="mt-n3">
279 <pngx-input-select i18n-title title="" multiple="true" [items]="customFields" formControlName="remove_custom_fields"></pngx-input-select>
280 </div>
281 </div>
282 <div class="col">
283 <h6 class="form-label" i18n>Remove owners</h6>
284 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_owners"></pngx-input-switch>
285 <div class="mt-n3">
286 <pngx-input-select i18n-title title="" multiple="true" [items]="users" bindLabel="username" formControlName="remove_owners"></pngx-input-select>
287 </div>
288
289 <h6 class="form-label" i18n>Remove permissions</h6>
290 <pngx-input-switch i18n-title title="Remove all" [horizontal]="true" formControlName="remove_all_permissions"></pngx-input-switch>
291 <div>
292 <label class="form-label" i18n>View permissions</label>
293 <div class="mb-2">
294 <div class="row mb-1">
295 <div class="col-lg-3">
296 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
297 </div>
298 <div class="col-lg-9">
299 <pngx-permissions-user type="view" formControlName="remove_view_users"></pngx-permissions-user>
300 </div>
301 </div>
302 <div class="row">
303 <div class="col-lg-3">
304 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
305 </div>
306 <div class="col-lg-9">
307 <pngx-permissions-group type="view" formControlName="remove_view_groups"></pngx-permissions-group>
308 </div>
309 </div>
310 </div>
311 <label class="form-label" i18n>Edit permissions</label>
312 <div>
313 <div class="row mb-1">
314 <div class="col-lg-3">
315 <label class="form-label d-block my-2 text-nowrap" i18n>Users:</label>
316 </div>
317 <div class="col-lg-9">
318 <pngx-permissions-user type="change" formControlName="remove_change_users"></pngx-permissions-user>
319 </div>
320 </div>
321 <div class="row">
322 <div class="col-lg-3">
323 <label class="form-label d-block my-2 text-nowrap" i18n>Groups:</label>
324 </div>
325 <div class="col-lg-9">
326 <pngx-permissions-group type="change" formControlName="remove_change_groups"></pngx-permissions-group>
327 </div>
328 </div>
329 <small class="form-text text-muted text-end d-block" i18n>Edit permissions also grant viewing permissions</small>
330 </div>
331 </div>
332 </div>
333 </div>
334 }
335 @case (WorkflowActionType.Email) {
336 <div class="row" [formGroup]="formGroup.get('email')">
337 <input type="hidden" formControlName="id" />
338 <div class="col">
339 <pngx-input-text i18n-title title="Email subject" formControlName="subject" [error]="error?.actions?.[i]?.email?.subject"></pngx-input-text>
340 <pngx-input-textarea i18n-title title="Email body" formControlName="body" [error]="error?.actions?.[i]?.email?.body"></pngx-input-textarea>
341 <pngx-input-text i18n-title title="Email recipients" formControlName="to" [error]="error?.actions?.[i]?.email?.to"></pngx-input-text>
342 <pngx-input-switch i18n-title title="Attach document" formControlName="include_document"></pngx-input-switch>
343 </div>
344 </div>
345 }
346 @case (WorkflowActionType.Webhook) {
347 <div class="row" [formGroup]="formGroup.get('webhook')">
348 <input type="hidden" formControlName="id" />
349 <div class="col">
350 <pngx-input-text i18n-title title="Webhook url" formControlName="url" [error]="error?.actions?.[i]?.url"></pngx-input-text>
351 <div class="d-flex">
352 <pngx-input-switch i18n-title title="Use parameters for webhook body" formControlName="use_params" [horizontal]="true"></pngx-input-switch>
353 <pngx-input-switch i18n-title title="Send webhook payload as JSON" formControlName="as_json" [horizontal]="true" class="ms-5"></pngx-input-switch>
354 </div>
355 @if (formGroup.get('webhook').value['use_params']) {
356 <pngx-input-entries i18n-title title="Webhook params" formControlName="params" [error]="error?.actions?.[i]?.params"></pngx-input-entries>
357 } @else {
358 <pngx-input-textarea i18n-title title="Webhook body" formControlName="body" [error]="error?.actions?.[i]?.body"></pngx-input-textarea>
359 }
360 <pngx-input-entries i18n-title title="Webhook headers" formControlName="headers" [error]="error?.actions?.[i]?.headers"></pngx-input-entries>
361 <pngx-input-switch i18n-title title="Include document" formControlName="include_document"></pngx-input-switch>
362 </div>
363 </div>
364 }
365 }
366 </div>
367 </ng-template>