@epistola.app/valtimo-plugin 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -13
- package/ng-package.json +0 -17
- package/src/lib/assets/epistola-logo.ts +0 -4
- package/src/lib/assets/index.ts +0 -1
- package/src/lib/components/check-job-status-configuration/check-job-status-configuration.component.html +0 -51
- package/src/lib/components/check-job-status-configuration/check-job-status-configuration.component.scss +0 -1
- package/src/lib/components/check-job-status-configuration/check-job-status-configuration.component.ts +0 -71
- package/src/lib/components/data-mapping-tree/data-mapping-tree.component.html +0 -23
- package/src/lib/components/data-mapping-tree/data-mapping-tree.component.scss +0 -38
- package/src/lib/components/data-mapping-tree/data-mapping-tree.component.ts +0 -124
- package/src/lib/components/download-document-configuration/download-document-configuration.component.html +0 -29
- package/src/lib/components/download-document-configuration/download-document-configuration.component.scss +0 -1
- package/src/lib/components/download-document-configuration/download-document-configuration.component.ts +0 -71
- package/src/lib/components/epistola-configuration/epistola-configuration.component.html +0 -74
- package/src/lib/components/epistola-configuration/epistola-configuration.component.scss +0 -1
- package/src/lib/components/epistola-configuration/epistola-configuration.component.ts +0 -96
- package/src/lib/components/epistola-download/epistola-download.component.ts +0 -79
- package/src/lib/components/epistola-download/epistola-download.formio.ts +0 -19
- package/src/lib/components/field-tree/field-tree.component.html +0 -192
- package/src/lib/components/field-tree/field-tree.component.scss +0 -255
- package/src/lib/components/field-tree/field-tree.component.ts +0 -321
- package/src/lib/components/generate-document-configuration/generate-document-configuration.component.html +0 -182
- package/src/lib/components/generate-document-configuration/generate-document-configuration.component.scss +0 -150
- package/src/lib/components/generate-document-configuration/generate-document-configuration.component.ts +0 -422
- package/src/lib/epistola.module.ts +0 -50
- package/src/lib/epistola.specification.ts +0 -208
- package/src/lib/models/config.ts +0 -53
- package/src/lib/models/index.ts +0 -2
- package/src/lib/models/template.ts +0 -70
- package/src/lib/services/epistola-plugin.service.ts +0 -82
- package/src/lib/services/index.ts +0 -1
- package/src/public_api.ts +0 -16
- package/tsconfig.lib.json +0 -21
- /package/{dist/fesm2022 → fesm2022}/epistola.app-valtimo-plugin.mjs +0 -0
- /package/{dist/fesm2022 → fesm2022}/epistola.app-valtimo-plugin.mjs.map +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/lib → lib}/assets/epistola-logo.d.ts +0 -0
- /package/{dist/lib → lib}/assets/index.d.ts +0 -0
- /package/{dist/lib → lib}/components/check-job-status-configuration/check-job-status-configuration.component.d.ts +0 -0
- /package/{dist/lib → lib}/components/data-mapping-tree/data-mapping-tree.component.d.ts +0 -0
- /package/{dist/lib → lib}/components/download-document-configuration/download-document-configuration.component.d.ts +0 -0
- /package/{dist/lib → lib}/components/epistola-configuration/epistola-configuration.component.d.ts +0 -0
- /package/{dist/lib → lib}/components/epistola-download/epistola-download.component.d.ts +0 -0
- /package/{dist/lib → lib}/components/epistola-download/epistola-download.formio.d.ts +0 -0
- /package/{dist/lib → lib}/components/field-tree/field-tree.component.d.ts +0 -0
- /package/{dist/lib → lib}/components/generate-document-configuration/generate-document-configuration.component.d.ts +0 -0
- /package/{dist/lib → lib}/epistola.module.d.ts +0 -0
- /package/{dist/lib → lib}/epistola.specification.d.ts +0 -0
- /package/{dist/lib → lib}/models/config.d.ts +0 -0
- /package/{dist/lib → lib}/models/index.d.ts +0 -0
- /package/{dist/lib → lib}/models/template.d.ts +0 -0
- /package/{dist/lib → lib}/services/epistola-plugin.service.d.ts +0 -0
- /package/{dist/lib → lib}/services/index.d.ts +0 -0
- /package/{dist/public_api.d.ts → public_api.d.ts} +0 -0
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core';
|
|
2
|
-
import {CommonModule} from '@angular/common';
|
|
3
|
-
import {FormsModule} from '@angular/forms';
|
|
4
|
-
import {PluginTranslatePipeModule} from '@valtimo/plugin';
|
|
5
|
-
import {InputModule, ValuePathSelectorComponent, ValuePathSelectorPrefix} from '@valtimo/components';
|
|
6
|
-
import {TemplateField} from '../../models';
|
|
7
|
-
|
|
8
|
-
export type InputMode = 'browse' | 'pv' | 'expression';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Recursive component that renders a single TemplateField node as part of a tree form.
|
|
12
|
-
*
|
|
13
|
-
* - SCALAR fields render as a label + input row with a 3-mode selector (browse / pv / expression)
|
|
14
|
-
* - OBJECT fields render as a collapsible section with children indented inside
|
|
15
|
-
* - ARRAY fields render as a collapsible section with source collection input and optional per-item field mappings
|
|
16
|
-
*
|
|
17
|
-
* Input modes:
|
|
18
|
-
* - Browse (⊞): ValuePathSelector for doc:/case: paths
|
|
19
|
-
* - PV (pv): Dropdown of discovered process variables (text fallback when none found)
|
|
20
|
-
* - Expression (fx): Free-text input for manual expressions
|
|
21
|
-
*/
|
|
22
|
-
@Component({
|
|
23
|
-
selector: 'epistola-field-tree',
|
|
24
|
-
templateUrl: './field-tree.component.html',
|
|
25
|
-
styleUrls: ['./field-tree.component.scss'],
|
|
26
|
-
standalone: true,
|
|
27
|
-
imports: [
|
|
28
|
-
CommonModule,
|
|
29
|
-
FormsModule,
|
|
30
|
-
PluginTranslatePipeModule,
|
|
31
|
-
InputModule,
|
|
32
|
-
ValuePathSelectorComponent
|
|
33
|
-
]
|
|
34
|
-
})
|
|
35
|
-
export class FieldTreeComponent implements OnChanges {
|
|
36
|
-
@Input() field!: TemplateField;
|
|
37
|
-
@Input() value: any = undefined;
|
|
38
|
-
@Input() pluginId!: string;
|
|
39
|
-
@Input() caseDefinitionKey: string | null = null;
|
|
40
|
-
@Input() processVariables: string[] = [];
|
|
41
|
-
@Input() disabled = false;
|
|
42
|
-
|
|
43
|
-
@Output() valueChange = new EventEmitter<any>();
|
|
44
|
-
|
|
45
|
-
readonly ValuePathSelectorPrefix = ValuePathSelectorPrefix;
|
|
46
|
-
|
|
47
|
-
inputMode: InputMode = 'browse';
|
|
48
|
-
expanded = false;
|
|
49
|
-
|
|
50
|
-
/** For ARRAY fields: whether to show per-item field mapping */
|
|
51
|
-
arrayPerFieldMode = false;
|
|
52
|
-
|
|
53
|
-
/** Completeness badge for collapsed object/array sections */
|
|
54
|
-
mappedCount = 0;
|
|
55
|
-
totalRequired = 0;
|
|
56
|
-
|
|
57
|
-
ngOnChanges(changes: SimpleChanges): void {
|
|
58
|
-
if (changes['value'] || changes['field']) {
|
|
59
|
-
this.updateCompleteness();
|
|
60
|
-
// Auto-expand if there are unmapped required children
|
|
61
|
-
if (!this.expanded && this.totalRequired > 0 && this.mappedCount < this.totalRequired) {
|
|
62
|
-
this.expanded = true;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// Detect input mode from prefill value
|
|
66
|
-
if (changes['value'] && this.value != null) {
|
|
67
|
-
if (this.field?.fieldType === 'SCALAR') {
|
|
68
|
-
this.inputMode = this.detectInputMode(this.value);
|
|
69
|
-
} else if (this.field?.fieldType === 'ARRAY') {
|
|
70
|
-
const sourceValue = this.getSourceValue();
|
|
71
|
-
if (sourceValue) {
|
|
72
|
-
this.inputMode = this.detectInputMode(sourceValue);
|
|
73
|
-
}
|
|
74
|
-
// Detect per-field mode from value shape
|
|
75
|
-
if (typeof this.value === 'object' && this.value !== null && '_source' in this.value) {
|
|
76
|
-
this.arrayPerFieldMode = true;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
toggleExpanded(): void {
|
|
83
|
-
this.expanded = !this.expanded;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
setInputMode(mode: InputMode): void {
|
|
87
|
-
this.inputMode = mode;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** Handle value change from ValuePathSelector (browse mode) */
|
|
91
|
-
onBrowseValueChange(newValue: string): void {
|
|
92
|
-
this.emitScalarValue(newValue);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** Handle value change from PV dropdown */
|
|
96
|
-
onPvChange(newValue: string): void {
|
|
97
|
-
if (newValue) {
|
|
98
|
-
this.emitScalarValue('pv:' + newValue);
|
|
99
|
-
} else {
|
|
100
|
-
this.emitScalarValue('');
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** Handle value change from text input (expression mode) */
|
|
105
|
-
onExpressionValueChange(newValue: string): void {
|
|
106
|
-
this.emitScalarValue(newValue);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Handle child value change for OBJECT fields */
|
|
110
|
-
onChildChange(childName: string, childValue: any): void {
|
|
111
|
-
const current = (typeof this.value === 'object' && this.value !== null) ? {...this.value} : {};
|
|
112
|
-
if (childValue === undefined || childValue === null || childValue === '') {
|
|
113
|
-
delete current[childName];
|
|
114
|
-
} else {
|
|
115
|
-
current[childName] = childValue;
|
|
116
|
-
}
|
|
117
|
-
this.valueChange.emit(Object.keys(current).length > 0 ? current : undefined);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** Get the current value for a child field within an OBJECT */
|
|
121
|
-
getChildValue(childName: string): any {
|
|
122
|
-
if (typeof this.value === 'object' && this.value !== null) {
|
|
123
|
-
return this.value[childName];
|
|
124
|
-
}
|
|
125
|
-
return undefined;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** Get the string value for display (for SCALAR leaf inputs and direct array mode) */
|
|
129
|
-
getStringValue(): string {
|
|
130
|
-
return typeof this.value === 'string' ? this.value : '';
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Get the PV name from a pv: prefixed value (for PV dropdown default selection) */
|
|
134
|
-
getPvName(): string {
|
|
135
|
-
const str = this.getStringValue();
|
|
136
|
-
return str.startsWith('pv:') ? str.substring(3) : '';
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// --- ARRAY-specific methods ---
|
|
140
|
-
|
|
141
|
-
/** Get the source collection value (works for both direct string and _source format) */
|
|
142
|
-
getSourceValue(): string {
|
|
143
|
-
if (typeof this.value === 'string') {
|
|
144
|
-
return this.value;
|
|
145
|
-
}
|
|
146
|
-
if (typeof this.value === 'object' && this.value !== null && '_source' in this.value) {
|
|
147
|
-
return this.value['_source'] || '';
|
|
148
|
-
}
|
|
149
|
-
return '';
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** Get the PV name from the source value */
|
|
153
|
-
getSourcePvName(): string {
|
|
154
|
-
const source = this.getSourceValue();
|
|
155
|
-
return source.startsWith('pv:') ? source.substring(3) : '';
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
toggleArrayPerFieldMode(): void {
|
|
159
|
-
this.arrayPerFieldMode = !this.arrayPerFieldMode;
|
|
160
|
-
|
|
161
|
-
if (this.arrayPerFieldMode) {
|
|
162
|
-
// Switch from direct to per-field: convert string value to _source object
|
|
163
|
-
const currentSource = this.getSourceValue();
|
|
164
|
-
const obj: Record<string, any> = {_source: currentSource};
|
|
165
|
-
this.valueChange.emit(obj);
|
|
166
|
-
} else {
|
|
167
|
-
// Switch from per-field to direct: extract _source as string value
|
|
168
|
-
const source = this.getSourceValue();
|
|
169
|
-
this.valueChange.emit(source || undefined);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** Handle source collection value change (used in ARRAY mode) */
|
|
174
|
-
onSourceBrowseChange(newValue: string): void {
|
|
175
|
-
this.updateSourceValue(newValue);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
onSourcePvChange(newValue: string): void {
|
|
179
|
-
this.updateSourceValue(newValue ? 'pv:' + newValue : '');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
onSourceExpressionChange(newValue: string): void {
|
|
183
|
-
this.updateSourceValue(newValue);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/** Handle per-item field mapping change */
|
|
187
|
-
onItemFieldChange(childName: string, sourceFieldName: string): void {
|
|
188
|
-
const current = (typeof this.value === 'object' && this.value !== null) ? {...this.value} : {_source: ''};
|
|
189
|
-
if (sourceFieldName && sourceFieldName.trim().length > 0) {
|
|
190
|
-
current[childName] = sourceFieldName;
|
|
191
|
-
} else {
|
|
192
|
-
delete current[childName];
|
|
193
|
-
}
|
|
194
|
-
this.valueChange.emit(current);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/** Get the current source field name mapping for a child */
|
|
198
|
-
getItemFieldValue(childName: string): string {
|
|
199
|
-
if (typeof this.value === 'object' && this.value !== null) {
|
|
200
|
-
return this.value[childName] || '';
|
|
201
|
-
}
|
|
202
|
-
return '';
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/** Check if the array has any children that can be mapped per-item */
|
|
206
|
-
hasArrayChildren(): boolean {
|
|
207
|
-
return !!(this.field?.children && this.field.children.length > 0);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private emitScalarValue(newValue: string): void {
|
|
211
|
-
this.valueChange.emit(newValue || undefined);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
private updateSourceValue(newValue: string): void {
|
|
215
|
-
if (this.arrayPerFieldMode) {
|
|
216
|
-
const current = (typeof this.value === 'object' && this.value !== null) ? {...this.value} : {};
|
|
217
|
-
current['_source'] = newValue || '';
|
|
218
|
-
this.valueChange.emit(current);
|
|
219
|
-
} else {
|
|
220
|
-
this.valueChange.emit(newValue || undefined);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
private updateCompleteness(): void {
|
|
225
|
-
if (this.field?.fieldType === 'OBJECT' && this.field.children) {
|
|
226
|
-
const stats = this.countRequiredMapped(this.field.children, this.value || {});
|
|
227
|
-
this.mappedCount = stats.mapped;
|
|
228
|
-
this.totalRequired = stats.total;
|
|
229
|
-
} else if (this.field?.fieldType === 'ARRAY') {
|
|
230
|
-
this.updateArrayCompleteness();
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
private updateArrayCompleteness(): void {
|
|
235
|
-
if (!this.field?.children || this.field.children.length === 0) {
|
|
236
|
-
// No children: just check if source is set
|
|
237
|
-
this.totalRequired = this.field?.required ? 1 : 0;
|
|
238
|
-
this.mappedCount = this.getSourceValue() ? (this.field?.required ? 1 : 0) : 0;
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (typeof this.value === 'object' && this.value !== null && '_source' in this.value) {
|
|
243
|
-
// Per-field mode: count source + required children
|
|
244
|
-
let total = 0;
|
|
245
|
-
let mapped = 0;
|
|
246
|
-
|
|
247
|
-
// Source counts as 1 required
|
|
248
|
-
if (this.field?.required) {
|
|
249
|
-
total++;
|
|
250
|
-
if (this.value['_source'] && this.value['_source'].trim().length > 0) {
|
|
251
|
-
mapped++;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Count required children
|
|
256
|
-
for (const child of this.field.children) {
|
|
257
|
-
if (child.required) {
|
|
258
|
-
total++;
|
|
259
|
-
const val = this.value[child.name];
|
|
260
|
-
if (typeof val === 'string' && val.trim().length > 0) {
|
|
261
|
-
mapped++;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
this.mappedCount = mapped;
|
|
267
|
-
this.totalRequired = total;
|
|
268
|
-
} else {
|
|
269
|
-
// Direct mode: just check if source is set
|
|
270
|
-
this.totalRequired = this.field?.required ? 1 : 0;
|
|
271
|
-
this.mappedCount = this.getSourceValue() ? (this.field?.required ? 1 : 0) : 0;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private countRequiredMapped(
|
|
276
|
-
fields: TemplateField[],
|
|
277
|
-
mapping: Record<string, any>
|
|
278
|
-
): {mapped: number; total: number} {
|
|
279
|
-
let mapped = 0;
|
|
280
|
-
let total = 0;
|
|
281
|
-
for (const field of fields) {
|
|
282
|
-
if (field.fieldType === 'SCALAR' && field.required) {
|
|
283
|
-
total++;
|
|
284
|
-
const val = mapping[field.name];
|
|
285
|
-
if (typeof val === 'string' && val.trim().length > 0) {
|
|
286
|
-
mapped++;
|
|
287
|
-
}
|
|
288
|
-
} else if (field.fieldType === 'ARRAY' && field.required) {
|
|
289
|
-
total++;
|
|
290
|
-
const val = mapping[field.name];
|
|
291
|
-
if (typeof val === 'string' && val.trim().length > 0) {
|
|
292
|
-
mapped++;
|
|
293
|
-
} else if (typeof val === 'object' && val !== null && '_source' in val) {
|
|
294
|
-
if (typeof val['_source'] === 'string' && val['_source'].trim().length > 0) {
|
|
295
|
-
mapped++;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
} else if (field.fieldType === 'OBJECT' && field.children) {
|
|
299
|
-
const nested = (typeof mapping[field.name] === 'object' && mapping[field.name] !== null)
|
|
300
|
-
? mapping[field.name]
|
|
301
|
-
: {};
|
|
302
|
-
const childStats = this.countRequiredMapped(field.children, nested);
|
|
303
|
-
mapped += childStats.mapped;
|
|
304
|
-
total += childStats.total;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return {mapped, total};
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
private detectInputMode(value: any): InputMode {
|
|
311
|
-
if (typeof value !== 'string') return 'browse';
|
|
312
|
-
if (value.startsWith('doc:') || value.startsWith('case:')) return 'browse';
|
|
313
|
-
if (value.startsWith('pv:')) return 'pv';
|
|
314
|
-
if (value.length > 0) return 'expression';
|
|
315
|
-
return 'browse';
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
private isResolvableValue(value: string): boolean {
|
|
319
|
-
return value.startsWith('doc:') || value.startsWith('case:') || value.startsWith('pv:') || value.startsWith('template:');
|
|
320
|
-
}
|
|
321
|
-
}
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
<v-form
|
|
2
|
-
(valueChange)="formValueChange($event)"
|
|
3
|
-
*ngIf="{
|
|
4
|
-
disabled: disabled$ | async,
|
|
5
|
-
prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null,
|
|
6
|
-
templateOptions: templateOptions$ | async,
|
|
7
|
-
templatesLoading: templatesLoading$ | async,
|
|
8
|
-
variantOptions: variantOptions$ | async,
|
|
9
|
-
variantsLoading: variantsLoading$ | async,
|
|
10
|
-
environmentOptions: environmentOptions$ | async,
|
|
11
|
-
environmentsLoading: environmentsLoading$ | async,
|
|
12
|
-
templateFieldsLoading: templateFieldsLoading$ | async,
|
|
13
|
-
selectedTemplateId: selectedTemplateId$ | async
|
|
14
|
-
} as obs"
|
|
15
|
-
>
|
|
16
|
-
<v-select
|
|
17
|
-
name="templateId"
|
|
18
|
-
[title]="'templateId' | pluginTranslate: pluginId | async"
|
|
19
|
-
[tooltip]="'templateIdTooltip' | pluginTranslate: pluginId | async"
|
|
20
|
-
[margin]="true"
|
|
21
|
-
[items]="obs.templateOptions"
|
|
22
|
-
[defaultSelectionId]="obs.prefill?.templateId"
|
|
23
|
-
[disabled]="obs.disabled || obs.templatesLoading"
|
|
24
|
-
[required]="true"
|
|
25
|
-
[loading]="obs.templatesLoading"
|
|
26
|
-
>
|
|
27
|
-
</v-select>
|
|
28
|
-
|
|
29
|
-
<!-- Variant selection mode toggle -->
|
|
30
|
-
<div class="variant-mode-toggle" *ngIf="obs.selectedTemplateId">
|
|
31
|
-
<label class="variant-mode-label">{{ 'variantSelectionMode' | pluginTranslate: pluginId | async }}</label>
|
|
32
|
-
<div class="variant-mode-buttons">
|
|
33
|
-
<button
|
|
34
|
-
type="button"
|
|
35
|
-
class="variant-mode-btn"
|
|
36
|
-
[class.active]="variantSelectionMode === 'explicit'"
|
|
37
|
-
(click)="onVariantSelectionModeChange('explicit')"
|
|
38
|
-
[disabled]="obs.disabled"
|
|
39
|
-
>{{ 'selectByVariant' | pluginTranslate: pluginId | async }}</button>
|
|
40
|
-
<button
|
|
41
|
-
type="button"
|
|
42
|
-
class="variant-mode-btn"
|
|
43
|
-
[class.active]="variantSelectionMode === 'attributes'"
|
|
44
|
-
(click)="onVariantSelectionModeChange('attributes')"
|
|
45
|
-
[disabled]="obs.disabled"
|
|
46
|
-
>{{ 'selectByAttributes' | pluginTranslate: pluginId | async }}</button>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<!-- Explicit variant selection (dropdown) -->
|
|
51
|
-
<v-select
|
|
52
|
-
*ngIf="variantSelectionMode === 'explicit'"
|
|
53
|
-
name="variantId"
|
|
54
|
-
[title]="'variantId' | pluginTranslate: pluginId | async"
|
|
55
|
-
[tooltip]="'variantIdTooltip' | pluginTranslate: pluginId | async"
|
|
56
|
-
[margin]="true"
|
|
57
|
-
[items]="obs.variantOptions"
|
|
58
|
-
[defaultSelectionId]="obs.prefill?.variantId"
|
|
59
|
-
[disabled]="obs.disabled || obs.variantsLoading || !obs.selectedTemplateId"
|
|
60
|
-
[required]="false"
|
|
61
|
-
[loading]="obs.variantsLoading"
|
|
62
|
-
>
|
|
63
|
-
</v-select>
|
|
64
|
-
|
|
65
|
-
<!-- Attribute-based variant selection -->
|
|
66
|
-
<div *ngIf="variantSelectionMode === 'attributes' && obs.selectedTemplateId" class="variant-attributes-section">
|
|
67
|
-
<label class="variant-attributes-label">{{ 'variantAttributes' | pluginTranslate: pluginId | async }}</label>
|
|
68
|
-
<div class="variant-attributes-list">
|
|
69
|
-
<div *ngFor="let entry of variantAttributeEntries; let i = index" class="variant-attribute-row">
|
|
70
|
-
<input
|
|
71
|
-
type="text"
|
|
72
|
-
class="variant-attribute-input"
|
|
73
|
-
[placeholder]="'attributeKey' | pluginTranslate: pluginId | async"
|
|
74
|
-
[(ngModel)]="entry.key"
|
|
75
|
-
(ngModelChange)="onAttributeEntryChange()"
|
|
76
|
-
[disabled]="obs.disabled"
|
|
77
|
-
/>
|
|
78
|
-
<input
|
|
79
|
-
type="text"
|
|
80
|
-
class="variant-attribute-input"
|
|
81
|
-
[placeholder]="'attributeValue' | pluginTranslate: pluginId | async"
|
|
82
|
-
[(ngModel)]="entry.value"
|
|
83
|
-
(ngModelChange)="onAttributeEntryChange()"
|
|
84
|
-
[disabled]="obs.disabled"
|
|
85
|
-
/>
|
|
86
|
-
<button
|
|
87
|
-
type="button"
|
|
88
|
-
class="variant-attribute-remove-btn"
|
|
89
|
-
(click)="removeAttributeEntry(i)"
|
|
90
|
-
[disabled]="obs.disabled"
|
|
91
|
-
title="{{ 'removeAttribute' | pluginTranslate: pluginId | async }}"
|
|
92
|
-
>×</button>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
<button
|
|
96
|
-
type="button"
|
|
97
|
-
class="variant-attribute-add-btn"
|
|
98
|
-
(click)="addAttributeEntry()"
|
|
99
|
-
[disabled]="obs.disabled"
|
|
100
|
-
>+ {{ 'addAttribute' | pluginTranslate: pluginId | async }}</button>
|
|
101
|
-
</div>
|
|
102
|
-
|
|
103
|
-
<v-select
|
|
104
|
-
name="environmentId"
|
|
105
|
-
[title]="'environmentId' | pluginTranslate: pluginId | async"
|
|
106
|
-
[tooltip]="'environmentIdTooltip' | pluginTranslate: pluginId | async"
|
|
107
|
-
[margin]="true"
|
|
108
|
-
[items]="obs.environmentOptions"
|
|
109
|
-
[defaultSelectionId]="obs.prefill?.environmentId"
|
|
110
|
-
[disabled]="obs.disabled || obs.environmentsLoading"
|
|
111
|
-
[required]="false"
|
|
112
|
-
[loading]="obs.environmentsLoading"
|
|
113
|
-
>
|
|
114
|
-
</v-select>
|
|
115
|
-
|
|
116
|
-
<v-select
|
|
117
|
-
name="outputFormat"
|
|
118
|
-
[title]="'outputFormat' | pluginTranslate: pluginId | async"
|
|
119
|
-
[tooltip]="'outputFormatTooltip' | pluginTranslate: pluginId | async"
|
|
120
|
-
[margin]="true"
|
|
121
|
-
[items]="outputFormatOptions"
|
|
122
|
-
[defaultSelectionId]="obs.prefill?.outputFormat || 'PDF'"
|
|
123
|
-
[disabled]="obs.disabled"
|
|
124
|
-
[required]="true"
|
|
125
|
-
>
|
|
126
|
-
</v-select>
|
|
127
|
-
|
|
128
|
-
<v-input
|
|
129
|
-
name="filename"
|
|
130
|
-
[title]="'filename' | pluginTranslate: pluginId | async"
|
|
131
|
-
[tooltip]="'filenameTooltip' | pluginTranslate: pluginId | async"
|
|
132
|
-
[margin]="true"
|
|
133
|
-
[defaultValue]="obs.prefill?.filename"
|
|
134
|
-
[disabled]="obs.disabled"
|
|
135
|
-
[required]="true"
|
|
136
|
-
>
|
|
137
|
-
</v-input>
|
|
138
|
-
|
|
139
|
-
<v-input
|
|
140
|
-
name="correlationId"
|
|
141
|
-
[title]="'correlationId' | pluginTranslate: pluginId | async"
|
|
142
|
-
[tooltip]="'correlationIdTooltip' | pluginTranslate: pluginId | async"
|
|
143
|
-
[margin]="true"
|
|
144
|
-
[defaultValue]="obs.prefill?.correlationId"
|
|
145
|
-
[disabled]="obs.disabled"
|
|
146
|
-
[required]="false"
|
|
147
|
-
>
|
|
148
|
-
</v-input>
|
|
149
|
-
|
|
150
|
-
<v-input
|
|
151
|
-
name="resultProcessVariable"
|
|
152
|
-
[title]="'resultProcessVariable' | pluginTranslate: pluginId | async"
|
|
153
|
-
[tooltip]="'resultProcessVariableTooltip' | pluginTranslate: pluginId | async"
|
|
154
|
-
[margin]="true"
|
|
155
|
-
[defaultValue]="obs.prefill?.resultProcessVariable"
|
|
156
|
-
[disabled]="obs.disabled"
|
|
157
|
-
[required]="true"
|
|
158
|
-
>
|
|
159
|
-
</v-input>
|
|
160
|
-
</v-form>
|
|
161
|
-
|
|
162
|
-
<epistola-data-mapping-tree
|
|
163
|
-
*ngIf="(selectedTemplateId$ | async)"
|
|
164
|
-
[pluginId]="pluginId"
|
|
165
|
-
[templateFields$]="templateFields$"
|
|
166
|
-
[disabled$]="disabled$"
|
|
167
|
-
[prefillMapping$]="prefillDataMapping$"
|
|
168
|
-
[caseDefinitionKey]="caseDefinitionKey"
|
|
169
|
-
[processVariables]="processVariables"
|
|
170
|
-
(mappingChange)="onDataMappingChange($event)"
|
|
171
|
-
(requiredFieldsStatus)="onRequiredFieldsStatusChange($event)"
|
|
172
|
-
></epistola-data-mapping-tree>
|
|
173
|
-
|
|
174
|
-
<div class="validation-summary" *ngIf="(selectedTemplateId$ | async) && requiredFieldsStatus.total > 0">
|
|
175
|
-
<span *ngIf="requiredFieldsStatus.mapped === requiredFieldsStatus.total" class="validation-complete">
|
|
176
|
-
{{ 'requiredFieldsComplete' | pluginTranslate: pluginId | async }}
|
|
177
|
-
</span>
|
|
178
|
-
<span *ngIf="requiredFieldsStatus.mapped < requiredFieldsStatus.total" class="validation-incomplete">
|
|
179
|
-
{{ requiredFieldsStatus.mapped }} / {{ requiredFieldsStatus.total }}
|
|
180
|
-
{{ 'validationSummary' | pluginTranslate: pluginId | async }}
|
|
181
|
-
</span>
|
|
182
|
-
</div>
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
.validation-summary {
|
|
2
|
-
margin-top: 0.5rem;
|
|
3
|
-
padding: 0.5rem 0.75rem;
|
|
4
|
-
border-radius: 4px;
|
|
5
|
-
font-size: 0.875rem;
|
|
6
|
-
|
|
7
|
-
.validation-complete {
|
|
8
|
-
color: #198754;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.validation-incomplete {
|
|
12
|
-
color: #dc3545;
|
|
13
|
-
font-weight: 500;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.variant-mode-toggle {
|
|
18
|
-
margin-bottom: 1rem;
|
|
19
|
-
padding: 0 0.75rem;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.variant-mode-label {
|
|
23
|
-
display: block;
|
|
24
|
-
font-size: 0.875rem;
|
|
25
|
-
font-weight: 500;
|
|
26
|
-
margin-bottom: 0.375rem;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.variant-mode-buttons {
|
|
30
|
-
display: flex;
|
|
31
|
-
gap: 0;
|
|
32
|
-
border: 1px solid #d1d5db;
|
|
33
|
-
border-radius: 4px;
|
|
34
|
-
overflow: hidden;
|
|
35
|
-
width: fit-content;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.variant-mode-btn {
|
|
39
|
-
padding: 0.375rem 0.75rem;
|
|
40
|
-
font-size: 0.8125rem;
|
|
41
|
-
background: #fff;
|
|
42
|
-
border: none;
|
|
43
|
-
border-right: 1px solid #d1d5db;
|
|
44
|
-
cursor: pointer;
|
|
45
|
-
color: #374151;
|
|
46
|
-
transition: background-color 0.15s, color 0.15s;
|
|
47
|
-
|
|
48
|
-
&:last-child {
|
|
49
|
-
border-right: none;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
&:hover:not([disabled]) {
|
|
53
|
-
background: #f3f4f6;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
&.active {
|
|
57
|
-
background: #2563eb;
|
|
58
|
-
color: #fff;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
&[disabled] {
|
|
62
|
-
opacity: 0.5;
|
|
63
|
-
cursor: not-allowed;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.variant-attributes-section {
|
|
68
|
-
margin-bottom: 1rem;
|
|
69
|
-
padding: 0 0.75rem;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.variant-attributes-label {
|
|
73
|
-
display: block;
|
|
74
|
-
font-size: 0.875rem;
|
|
75
|
-
font-weight: 500;
|
|
76
|
-
margin-bottom: 0.375rem;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.variant-attributes-list {
|
|
80
|
-
display: flex;
|
|
81
|
-
flex-direction: column;
|
|
82
|
-
gap: 0.375rem;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.variant-attribute-row {
|
|
86
|
-
display: flex;
|
|
87
|
-
gap: 0.375rem;
|
|
88
|
-
align-items: center;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.variant-attribute-input {
|
|
92
|
-
flex: 1;
|
|
93
|
-
padding: 0.375rem 0.5rem;
|
|
94
|
-
font-size: 0.8125rem;
|
|
95
|
-
border: 1px solid #d1d5db;
|
|
96
|
-
border-radius: 4px;
|
|
97
|
-
outline: none;
|
|
98
|
-
|
|
99
|
-
&:focus {
|
|
100
|
-
border-color: #2563eb;
|
|
101
|
-
box-shadow: 0 0 0 1px #2563eb;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
&[disabled] {
|
|
105
|
-
opacity: 0.5;
|
|
106
|
-
background: #f9fafb;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.variant-attribute-remove-btn {
|
|
111
|
-
padding: 0.25rem 0.5rem;
|
|
112
|
-
font-size: 1rem;
|
|
113
|
-
line-height: 1;
|
|
114
|
-
background: none;
|
|
115
|
-
border: 1px solid #d1d5db;
|
|
116
|
-
border-radius: 4px;
|
|
117
|
-
cursor: pointer;
|
|
118
|
-
color: #6b7280;
|
|
119
|
-
|
|
120
|
-
&:hover:not([disabled]) {
|
|
121
|
-
color: #dc3545;
|
|
122
|
-
border-color: #dc3545;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
&[disabled] {
|
|
126
|
-
opacity: 0.5;
|
|
127
|
-
cursor: not-allowed;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.variant-attribute-add-btn {
|
|
132
|
-
margin-top: 0.375rem;
|
|
133
|
-
padding: 0.25rem 0.5rem;
|
|
134
|
-
font-size: 0.8125rem;
|
|
135
|
-
background: none;
|
|
136
|
-
border: 1px dashed #d1d5db;
|
|
137
|
-
border-radius: 4px;
|
|
138
|
-
cursor: pointer;
|
|
139
|
-
color: #6b7280;
|
|
140
|
-
|
|
141
|
-
&:hover:not([disabled]) {
|
|
142
|
-
color: #2563eb;
|
|
143
|
-
border-color: #2563eb;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
&[disabled] {
|
|
147
|
-
opacity: 0.5;
|
|
148
|
-
cursor: not-allowed;
|
|
149
|
-
}
|
|
150
|
-
}
|