@epistola.app/valtimo-plugin 0.2.3 → 0.3.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, Output, Input, Component, NgModule } from '@angular/core';
2
+ import { Injectable, EventEmitter, Output, Input, Component, ChangeDetectionStrategy, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
4
  import { HttpClientModule } from '@angular/common/http';
5
5
  import * as i2 from '@valtimo/shared';
@@ -10,10 +10,13 @@ import { PluginTranslatePipeModule } from '@valtimo/plugin';
10
10
  import * as i3 from '@valtimo/components';
11
11
  import { FormModule, InputModule, ValuePathSelectorPrefix, ValuePathSelectorComponent, SelectModule, registerCustomFormioComponent } from '@valtimo/components';
12
12
  import { BehaviorSubject, combineLatest, take, Subject, merge, of } from 'rxjs';
13
- import { startWith, delay, takeUntil, filter, map, catchError, take as take$1 } from 'rxjs/operators';
13
+ import { startWith, delay, takeUntil, filter, map, catchError, take as take$1, debounceTime } from 'rxjs/operators';
14
14
  import * as i4 from '@angular/forms';
15
15
  import { FormsModule } from '@angular/forms';
16
16
  import * as i2$2 from '@valtimo/process-link';
17
+ import * as i7 from '@formio/angular';
18
+ import { FormioModule } from '@formio/angular';
19
+ import * as i4$1 from '@angular/platform-browser';
17
20
 
18
21
  /**
19
22
  * Service for interacting with Epistola plugin API endpoints.
@@ -65,10 +68,36 @@ class EpistolaPluginService {
65
68
  validateMapping(pluginConfigurationId, templateId, dataMapping) {
66
69
  return this.http.post(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/templates/${templateId}/validate-mapping`, { dataMapping });
67
70
  }
68
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaPluginService, deps: [{ token: i1.HttpClient }, { token: i2.ConfigService }], target: i0.ɵɵFactoryTarget.Injectable });
69
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaPluginService });
71
+ /**
72
+ * Get a dynamically generated Formio form for retrying a failed document generation.
73
+ */
74
+ getRetryForm(processInstanceId, documentId, sourceActivityId) {
75
+ const params = { processInstanceId };
76
+ if (documentId) {
77
+ params['documentId'] = documentId;
78
+ }
79
+ if (sourceActivityId) {
80
+ params['sourceActivityId'] = sourceActivityId;
81
+ }
82
+ return this.http.get(`${this.apiEndpoint}/retry-form`, { params });
83
+ }
84
+ /**
85
+ * Preview a document by dry-running the generate-document process link.
86
+ * Returns the resolved data as a mock preview (Phase 1).
87
+ */
88
+ previewDocument(documentId, processDefinitionKey, sourceActivityId, processInstanceId, overrides) {
89
+ return this.http.post(`${this.apiEndpoint}/preview`, {
90
+ documentId,
91
+ processDefinitionKey,
92
+ sourceActivityId,
93
+ processInstanceId: processInstanceId || null,
94
+ overrides: overrides || null
95
+ });
96
+ }
97
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginService, deps: [{ token: i1.HttpClient }, { token: i2.ConfigService }], target: i0.ɵɵFactoryTarget.Injectable });
98
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginService });
70
99
  }
71
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaPluginService, decorators: [{
100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginService, decorators: [{
72
101
  type: Injectable
73
102
  }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.ConfigService }] });
74
103
 
@@ -132,10 +161,10 @@ class EpistolaConfigurationComponent {
132
161
  });
133
162
  });
134
163
  }
135
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
136
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: EpistolaConfigurationComponent, isStandalone: true, selector: "epistola-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"configurationTitle\"\n [title]=\"'configurationTitle' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.configurationTitle\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"baseUrl\"\n [title]=\"'baseUrl' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'baseUrlTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.baseUrl\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"apiKey\"\n [title]=\"'apiKey' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'apiKeyTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.apiKey\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n type=\"password\"\n >\n </v-input>\n\n <v-input\n name=\"tenantId\"\n [title]=\"'tenantId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'tenantIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.tenantId\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"defaultEnvironmentId\"\n [title]=\"'defaultEnvironmentId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'defaultEnvironmentIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.defaultEnvironmentId\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"templateSyncEnabled\"\n type=\"checkbox\"\n [title]=\"'templateSyncEnabled' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'templateSyncEnabledTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.templateSyncEnabled ? 'true' : ''\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n</v-form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }] });
164
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
165
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: EpistolaConfigurationComponent, isStandalone: true, selector: "epistola-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"configurationTitle\"\n [title]=\"'configurationTitle' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.configurationTitle\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"baseUrl\"\n [title]=\"'baseUrl' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'baseUrlTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.baseUrl\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"apiKey\"\n [title]=\"'apiKey' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'apiKeyTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.apiKey\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n type=\"password\"\n >\n </v-input>\n\n <v-input\n name=\"tenantId\"\n [title]=\"'tenantId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'tenantIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.tenantId\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"defaultEnvironmentId\"\n [title]=\"'defaultEnvironmentId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'defaultEnvironmentIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.defaultEnvironmentId\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"templateSyncEnabled\"\n type=\"checkbox\"\n [title]=\"'templateSyncEnabled' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'templateSyncEnabledTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.templateSyncEnabled ? 'true' : ''\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n</v-form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }] });
137
166
  }
138
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaConfigurationComponent, decorators: [{
167
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaConfigurationComponent, decorators: [{
139
168
  type: Component,
140
169
  args: [{ selector: 'epistola-configuration', standalone: true, imports: [CommonModule, PluginTranslatePipeModule, FormModule, InputModule], template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"configurationTitle\"\n [title]=\"'configurationTitle' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.configurationTitle\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"baseUrl\"\n [title]=\"'baseUrl' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'baseUrlTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.baseUrl\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"apiKey\"\n [title]=\"'apiKey' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'apiKeyTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.apiKey\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n type=\"password\"\n >\n </v-input>\n\n <v-input\n name=\"tenantId\"\n [title]=\"'tenantId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'tenantIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.tenantId\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"defaultEnvironmentId\"\n [title]=\"'defaultEnvironmentId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'defaultEnvironmentIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.defaultEnvironmentId\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"templateSyncEnabled\"\n type=\"checkbox\"\n [title]=\"'templateSyncEnabled' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'templateSyncEnabledTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.templateSyncEnabled ? 'true' : ''\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n</v-form>\n" }]
141
170
  }], propDecorators: { save$: [{
@@ -152,6 +181,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
152
181
  type: Output
153
182
  }] } });
154
183
 
184
+ function countRequiredMapped(fields, mapping) {
185
+ let mapped = 0;
186
+ let total = 0;
187
+ for (const field of fields) {
188
+ if (field.fieldType === 'SCALAR' && field.required) {
189
+ total++;
190
+ const val = mapping[field.name];
191
+ if (typeof val === 'string' && val.trim().length > 0) {
192
+ mapped++;
193
+ }
194
+ }
195
+ else if (field.fieldType === 'ARRAY' && field.required) {
196
+ total++;
197
+ const val = mapping[field.name];
198
+ if (typeof val === 'string' && val.trim().length > 0) {
199
+ mapped++;
200
+ }
201
+ else if (typeof val === 'object' && val !== null && '_source' in val) {
202
+ if (typeof val['_source'] === 'string' && val['_source'].trim().length > 0) {
203
+ mapped++;
204
+ }
205
+ }
206
+ }
207
+ else if (field.fieldType === 'OBJECT' && field.children) {
208
+ const nested = (typeof mapping[field.name] === 'object' && mapping[field.name] !== null)
209
+ ? mapping[field.name]
210
+ : {};
211
+ const childStats = countRequiredMapped(field.children, nested);
212
+ mapped += childStats.mapped;
213
+ total += childStats.total;
214
+ }
215
+ }
216
+ return { mapped, total };
217
+ }
218
+
155
219
  /**
156
220
  * Recursive component that renders a single TemplateField node as part of a tree form.
157
221
  *
@@ -332,7 +396,7 @@ class FieldTreeComponent {
332
396
  }
333
397
  updateCompleteness() {
334
398
  if (this.field?.fieldType === 'OBJECT' && this.field.children) {
335
- const stats = this.countRequiredMapped(this.field.children, this.value || {});
399
+ const stats = countRequiredMapped(this.field.children, this.value || {});
336
400
  this.mappedCount = stats.mapped;
337
401
  this.totalRequired = stats.total;
338
402
  }
@@ -377,40 +441,6 @@ class FieldTreeComponent {
377
441
  this.mappedCount = this.getSourceValue() ? (this.field?.required ? 1 : 0) : 0;
378
442
  }
379
443
  }
380
- countRequiredMapped(fields, mapping) {
381
- let mapped = 0;
382
- let total = 0;
383
- for (const field of fields) {
384
- if (field.fieldType === 'SCALAR' && field.required) {
385
- total++;
386
- const val = mapping[field.name];
387
- if (typeof val === 'string' && val.trim().length > 0) {
388
- mapped++;
389
- }
390
- }
391
- else if (field.fieldType === 'ARRAY' && field.required) {
392
- total++;
393
- const val = mapping[field.name];
394
- if (typeof val === 'string' && val.trim().length > 0) {
395
- mapped++;
396
- }
397
- else if (typeof val === 'object' && val !== null && '_source' in val) {
398
- if (typeof val['_source'] === 'string' && val['_source'].trim().length > 0) {
399
- mapped++;
400
- }
401
- }
402
- }
403
- else if (field.fieldType === 'OBJECT' && field.children) {
404
- const nested = (typeof mapping[field.name] === 'object' && mapping[field.name] !== null)
405
- ? mapping[field.name]
406
- : {};
407
- const childStats = this.countRequiredMapped(field.children, nested);
408
- mapped += childStats.mapped;
409
- total += childStats.total;
410
- }
411
- }
412
- return { mapped, total };
413
- }
414
444
  detectInputMode(value) {
415
445
  if (typeof value !== 'string')
416
446
  return 'browse';
@@ -425,12 +455,12 @@ class FieldTreeComponent {
425
455
  isResolvableValue(value) {
426
456
  return value.startsWith('doc:') || value.startsWith('case:') || value.startsWith('pv:') || value.startsWith('template:');
427
457
  }
428
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FieldTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
429
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FieldTreeComponent, isStandalone: true, selector: "epistola-field-tree", inputs: { field: "field", value: "value", pluginId: "pluginId", caseDefinitionKey: "caseDefinitionKey", processVariables: "processVariables", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<!-- SCALAR field: label row + input with 3-mode selector -->\n<div *ngIf=\"field.fieldType === 'SCALAR'\" class=\"field-row\" [class.field-required-unmapped]=\"field.required && !getStringValue()\">\n <div class=\"field-label\">\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-meta\">({{ field.type }}{{ field.required ? ', required' : '' }})</span>\n </div>\n <div class=\"field-input\">\n <div class=\"input-mode-group\">\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'browse'\" [disabled]=\"disabled\" (click)=\"setInputMode('browse')\" [title]=\"'browseMode' | pluginTranslate: pluginId | async\">\u229E</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'pv'\" [disabled]=\"disabled\" (click)=\"setInputMode('pv')\" [title]=\"'pvMode' | pluginTranslate: pluginId | async\">pv</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'expression'\" [disabled]=\"disabled\" (click)=\"setInputMode('expression')\" [title]=\"'expressionMode' | pluginTranslate: pluginId | async\">fx</button>\n </div>\n\n <!-- Browse mode: ValuePathSelector -->\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'browse'\">\n <valtimo-value-path-selector\n [name]=\"'field_' + field.path\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [prefixes]=\"[ValuePathSelectorPrefix.DOC, ValuePathSelectorPrefix.CASE]\"\n [notation]=\"'dots'\"\n [disabled]=\"disabled\"\n [defaultValue]=\"getStringValue()\"\n [showCaseDefinitionSelector]=\"!caseDefinitionKey\"\n (valueChangeEvent)=\"onBrowseValueChange($event)\"\n ></valtimo-value-path-selector>\n </div>\n\n <!-- PV mode: dropdown (when available) or text fallback -->\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'pv'\">\n <select\n *ngIf=\"processVariables.length > 0; else pvFallback\"\n class=\"pv-select\"\n [disabled]=\"disabled\"\n (change)=\"onPvChange($any($event.target).value)\"\n >\n <option value=\"\">{{ 'pvPlaceholder' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let pv of processVariables\" [value]=\"pv\" [selected]=\"pv === getPvName()\">{{ pv }}</option>\n </select>\n <ng-template #pvFallback>\n <v-input\n [name]=\"'pvfb_' + field.path\"\n [defaultValue]=\"getPvName()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'pvPlaceholder' | pluginTranslate: pluginId | async\"\n (valueChange)=\"onPvChange($event)\"\n ></v-input>\n </ng-template>\n </div>\n\n <!-- Expression mode: text input -->\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'expression'\">\n <v-input\n [name]=\"'fx_' + field.path\"\n [defaultValue]=\"getStringValue()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'e.g. pv:variableName or doc:path.to.field'\"\n (valueChange)=\"onExpressionValueChange($event)\"\n ></v-input>\n </div>\n </div>\n</div>\n\n<!-- OBJECT field: collapsible section with children -->\n<div *ngIf=\"field.fieldType === 'OBJECT'\" class=\"field-object\">\n <div class=\"field-object-header\" (click)=\"toggleExpanded()\" [class.field-required-unmapped]=\"totalRequired > 0 && mappedCount < totalRequired\">\n <span class=\"expand-icon\">{{ expanded ? '\u25BC' : '\u25B6' }}</span>\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-meta\">(object{{ field.required ? ', required' : '' }})</span>\n <span class=\"completeness-badge\" *ngIf=\"totalRequired > 0 && !expanded\">\n {{ mappedCount }}/{{ totalRequired }}\n </span>\n </div>\n <div class=\"field-object-children\" *ngIf=\"expanded\">\n <epistola-field-tree\n *ngFor=\"let child of field.children\"\n [field]=\"child\"\n [value]=\"getChildValue(child.name)\"\n [pluginId]=\"pluginId\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n [disabled]=\"disabled\"\n (valueChange)=\"onChildChange(child.name, $event)\"\n ></epistola-field-tree>\n </div>\n</div>\n\n<!-- ARRAY field: collapsible section with source collection + optional per-item mapping -->\n<div *ngIf=\"field.fieldType === 'ARRAY'\" class=\"field-array\">\n <div class=\"field-array-header\" (click)=\"toggleExpanded()\" [class.field-required-unmapped]=\"field.required && !getSourceValue()\">\n <span class=\"expand-icon\">{{ expanded ? '\u25BC' : '\u25B6' }}</span>\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-meta\">(array{{ field.required ? ', required' : '' }})</span>\n <span class=\"completeness-badge\" *ngIf=\"totalRequired > 0 && !expanded\">\n {{ mappedCount }}/{{ totalRequired }}\n </span>\n <span class=\"mapped-indicator\" *ngIf=\"totalRequired === 0 && getSourceValue() && !expanded\">\u2713</span>\n </div>\n <div class=\"field-array-content\" *ngIf=\"expanded\">\n <!-- Source collection input -->\n <div class=\"field-row\">\n <div class=\"field-label\">\n <span class=\"field-name\">{{ 'mapCollectionTo' | pluginTranslate: pluginId | async }}</span>\n </div>\n <div class=\"field-input\">\n <div class=\"input-mode-group\">\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'browse'\" [disabled]=\"disabled\" (click)=\"setInputMode('browse')\" [title]=\"'browseMode' | pluginTranslate: pluginId | async\">\u229E</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'pv'\" [disabled]=\"disabled\" (click)=\"setInputMode('pv')\" [title]=\"'pvMode' | pluginTranslate: pluginId | async\">pv</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'expression'\" [disabled]=\"disabled\" (click)=\"setInputMode('expression')\" [title]=\"'expressionMode' | pluginTranslate: pluginId | async\">fx</button>\n </div>\n\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'browse'\">\n <valtimo-value-path-selector\n [name]=\"'field_' + field.path\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [prefixes]=\"[ValuePathSelectorPrefix.DOC, ValuePathSelectorPrefix.CASE]\"\n [notation]=\"'dots'\"\n [disabled]=\"disabled\"\n [defaultValue]=\"getSourceValue()\"\n [showCaseDefinitionSelector]=\"!caseDefinitionKey\"\n (valueChangeEvent)=\"onSourceBrowseChange($event)\"\n ></valtimo-value-path-selector>\n </div>\n\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'pv'\">\n <select\n *ngIf=\"processVariables.length > 0; else pvSourceFallback\"\n class=\"pv-select\"\n [disabled]=\"disabled\"\n (change)=\"onSourcePvChange($any($event.target).value)\"\n >\n <option value=\"\">{{ 'pvPlaceholder' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let pv of processVariables\" [value]=\"pv\" [selected]=\"pv === getSourcePvName()\">{{ pv }}</option>\n </select>\n <ng-template #pvSourceFallback>\n <v-input\n [name]=\"'pvfb_' + field.path\"\n [defaultValue]=\"getSourcePvName()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'pvPlaceholder' | pluginTranslate: pluginId | async\"\n (valueChange)=\"onSourcePvChange($event)\"\n ></v-input>\n </ng-template>\n </div>\n\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'expression'\">\n <v-input\n [name]=\"'fx_' + field.path\"\n [defaultValue]=\"getSourceValue()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'e.g. pv:variableName or doc:path.to.field'\"\n (valueChange)=\"onSourceExpressionChange($event)\"\n ></v-input>\n </div>\n </div>\n </div>\n\n <!-- Per-item field mapping toggle (only shown when array has children) -->\n <div class=\"array-per-field-toggle\" *ngIf=\"hasArrayChildren()\">\n <label class=\"toggle-label\">\n <input\n type=\"checkbox\"\n [checked]=\"arrayPerFieldMode\"\n [disabled]=\"disabled\"\n (change)=\"toggleArrayPerFieldMode()\"\n />\n <span>{{ 'itemFieldMapping' | pluginTranslate: pluginId | async }}</span>\n </label>\n </div>\n\n <!-- Per-item field mappings -->\n <div class=\"array-item-fields\" *ngIf=\"arrayPerFieldMode && hasArrayChildren()\">\n <div class=\"item-fields-header\">\n <span class=\"item-fields-title\">{{ 'itemFieldMappingTitle' | pluginTranslate: pluginId | async }}</span>\n </div>\n <div class=\"item-field-row\" *ngFor=\"let child of field.children\">\n <div class=\"item-field-label\">\n <span class=\"field-name\">{{ child.name }}</span>\n <span class=\"field-meta\">({{ child.type }}{{ child.required ? ', required' : '' }})</span>\n </div>\n <div class=\"item-field-input\">\n <v-input\n [name]=\"'itemField_' + child.path\"\n [defaultValue]=\"getItemFieldValue(child.name)\"\n [disabled]=\"disabled\"\n [placeholder]=\"'sourceFieldPlaceholder' | pluginTranslate: pluginId | async\"\n (valueChange)=\"onItemFieldChange(child.name, $event)\"\n ></v-input>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".field-row{display:flex;align-items:flex-start;gap:.75rem;padding:.5rem 0;border-left:3px solid transparent}.field-row.field-required-unmapped{border-left-color:#dc3545;background-color:#fff5f5;padding-left:.5rem}.field-label{flex:0 0 200px;min-width:140px;padding-top:.5rem;word-break:break-word}.field-label .field-name{font-weight:500}.field-label .field-meta{font-size:.8125rem;color:#6c757d;margin-left:.25rem}.field-input{flex:1;display:flex;align-items:flex-start;gap:.5rem;min-width:0}.field-input-control{flex:1;min-width:0}.input-mode-group{flex:0 0 auto;display:flex;margin-top:.25rem;border:1px solid #c6c6c6;border-radius:4px;overflow:hidden}.input-mode-group .mode-btn{width:32px;height:32px;padding:0;border:none;border-right:1px solid #c6c6c6;background:#f4f4f4;color:#525252;font-size:.75rem;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color .15s}.input-mode-group .mode-btn:last-child{border-right:none}.input-mode-group .mode-btn:hover:not(:disabled){background:#e0e0e0}.input-mode-group .mode-btn.mode-active{background:#0f62fe;color:#fff}.input-mode-group .mode-btn.mode-active:hover:not(:disabled){background:#0353e9}.input-mode-group .mode-btn:disabled{opacity:.5;cursor:not-allowed}.pv-select{width:100%;height:2.5rem;padding:0 .75rem;border:1px solid #c6c6c6;border-radius:4px;background:#fff;color:#161616;font-size:.875rem;cursor:pointer}.pv-select:focus{outline:2px solid #0f62fe;outline-offset:-2px}.pv-select:disabled{opacity:.5;cursor:not-allowed;background:#f4f4f4}.field-object{margin:.25rem 0}.field-object-header,.field-array-header{display:flex;align-items:center;gap:.5rem;padding:.5rem .25rem;cursor:pointer;-webkit-user-select:none;user-select:none;border-left:3px solid transparent;border-radius:2px}.field-object-header:hover,.field-array-header:hover{background:#f4f4f4}.field-object-header.field-required-unmapped,.field-array-header.field-required-unmapped{border-left-color:#dc3545;background-color:#fff5f5}.field-object-header .expand-icon,.field-array-header .expand-icon{flex:0 0 1rem;font-size:.75rem;color:#525252}.field-object-header .field-name,.field-array-header .field-name{font-weight:500}.field-object-header .field-meta,.field-array-header .field-meta{font-size:.8125rem;color:#6c757d}.field-object-header .completeness-badge,.field-array-header .completeness-badge{margin-left:auto;font-size:.75rem;padding:.125rem .5rem;border-radius:10px;background:#e0e0e0;color:#525252;font-weight:500}.field-object-header .mapped-indicator,.field-array-header .mapped-indicator{margin-left:auto;color:#198754;font-weight:600}.field-object-children{padding-left:1.25rem;border-left:1px solid #e0e0e0;margin-left:.5rem}.field-array{margin:.25rem 0}.field-array-content{padding-left:1.25rem;border-left:1px solid #e0e0e0;margin-left:.5rem}.array-per-field-toggle{padding:.5rem 0}.array-per-field-toggle .toggle-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem;color:#525252}.array-per-field-toggle .toggle-label input[type=checkbox]{cursor:pointer}.array-item-fields{margin-left:.5rem;border-left:1px dashed #c6c6c6;padding:.25rem 0 .5rem 1rem}.item-fields-header{padding-bottom:.25rem}.item-fields-header .item-fields-title{font-size:.8125rem;font-weight:500;color:#6c757d}.item-field-row{display:flex;align-items:center;gap:.75rem;padding:.25rem 0}.item-field-label{flex:0 0 180px;min-width:120px;word-break:break-word}.item-field-label .field-name{font-weight:500;font-size:.875rem}.item-field-label .field-meta{font-size:.75rem;color:#6c757d;margin-left:.25rem}.item-field-input{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: FieldTreeComponent, selector: "epistola-field-tree", inputs: ["field", "value", "pluginId", "caseDefinitionKey", "processVariables", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }, { kind: "component", type: ValuePathSelectorComponent, selector: "valtimo-value-path-selector", inputs: ["name", "appendInline", "margin", "marginLg", "marginXl", "disabled", "caseDefinitionKey", "caseDefinitionVersionTag", "prefixes", "label", "tooltip", "required", "showCaseDefinitionSelector", "notation", "defaultValue", "type", "parentItem"], outputs: ["valueChangeEvent", "collectionSelected"] }] });
458
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FieldTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
459
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: FieldTreeComponent, isStandalone: true, selector: "epistola-field-tree", inputs: { field: "field", value: "value", pluginId: "pluginId", caseDefinitionKey: "caseDefinitionKey", processVariables: "processVariables", disabled: "disabled" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<!-- SCALAR field: label row + input with 3-mode selector -->\n<div *ngIf=\"field.fieldType === 'SCALAR'\" class=\"field-row\" [class.field-required-unmapped]=\"field.required && !getStringValue()\">\n <div class=\"field-label\">\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-meta\">({{ field.type }}{{ field.required ? ', required' : '' }})</span>\n </div>\n <div class=\"field-input\">\n <div class=\"input-mode-group\">\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'browse'\" [disabled]=\"disabled\" (click)=\"setInputMode('browse')\" [title]=\"'browseMode' | pluginTranslate: pluginId | async\">\u229E</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'pv'\" [disabled]=\"disabled\" (click)=\"setInputMode('pv')\" [title]=\"'pvMode' | pluginTranslate: pluginId | async\">pv</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'expression'\" [disabled]=\"disabled\" (click)=\"setInputMode('expression')\" [title]=\"'expressionMode' | pluginTranslate: pluginId | async\">fx</button>\n </div>\n\n <!-- Browse mode: ValuePathSelector -->\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'browse'\">\n <valtimo-value-path-selector\n [name]=\"'field_' + field.path\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [prefixes]=\"[ValuePathSelectorPrefix.DOC, ValuePathSelectorPrefix.CASE]\"\n [notation]=\"'dots'\"\n [disabled]=\"disabled\"\n [defaultValue]=\"getStringValue()\"\n [showCaseDefinitionSelector]=\"!caseDefinitionKey\"\n (valueChangeEvent)=\"onBrowseValueChange($event)\"\n ></valtimo-value-path-selector>\n </div>\n\n <!-- PV mode: dropdown (when available) or text fallback -->\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'pv'\">\n <select\n *ngIf=\"processVariables.length > 0; else pvFallback\"\n class=\"pv-select\"\n [disabled]=\"disabled\"\n (change)=\"onPvChange($any($event.target).value)\"\n >\n <option value=\"\">{{ 'pvPlaceholder' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let pv of processVariables\" [value]=\"pv\" [selected]=\"pv === getPvName()\">{{ pv }}</option>\n </select>\n <ng-template #pvFallback>\n <v-input\n [name]=\"'pvfb_' + field.path\"\n [defaultValue]=\"getPvName()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'pvPlaceholder' | pluginTranslate: pluginId | async\"\n (valueChange)=\"onPvChange($event)\"\n ></v-input>\n </ng-template>\n </div>\n\n <!-- Expression mode: text input -->\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'expression'\">\n <v-input\n [name]=\"'fx_' + field.path\"\n [defaultValue]=\"getStringValue()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'e.g. pv:variableName or doc:path.to.field'\"\n (valueChange)=\"onExpressionValueChange($event)\"\n ></v-input>\n </div>\n </div>\n</div>\n\n<!-- OBJECT field: collapsible section with children -->\n<div *ngIf=\"field.fieldType === 'OBJECT'\" class=\"field-object\">\n <div class=\"field-object-header\" (click)=\"toggleExpanded()\" [class.field-required-unmapped]=\"totalRequired > 0 && mappedCount < totalRequired\">\n <span class=\"expand-icon\">{{ expanded ? '\u25BC' : '\u25B6' }}</span>\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-meta\">(object{{ field.required ? ', required' : '' }})</span>\n <span class=\"completeness-badge\" *ngIf=\"totalRequired > 0 && !expanded\">\n {{ mappedCount }}/{{ totalRequired }}\n </span>\n </div>\n <div class=\"field-object-children\" *ngIf=\"expanded\">\n <epistola-field-tree\n *ngFor=\"let child of field.children\"\n [field]=\"child\"\n [value]=\"getChildValue(child.name)\"\n [pluginId]=\"pluginId\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n [disabled]=\"disabled\"\n (valueChange)=\"onChildChange(child.name, $event)\"\n ></epistola-field-tree>\n </div>\n</div>\n\n<!-- ARRAY field: collapsible section with source collection + optional per-item mapping -->\n<div *ngIf=\"field.fieldType === 'ARRAY'\" class=\"field-array\">\n <div class=\"field-array-header\" (click)=\"toggleExpanded()\" [class.field-required-unmapped]=\"field.required && !getSourceValue()\">\n <span class=\"expand-icon\">{{ expanded ? '\u25BC' : '\u25B6' }}</span>\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-meta\">(array{{ field.required ? ', required' : '' }})</span>\n <span class=\"completeness-badge\" *ngIf=\"totalRequired > 0 && !expanded\">\n {{ mappedCount }}/{{ totalRequired }}\n </span>\n <span class=\"mapped-indicator\" *ngIf=\"totalRequired === 0 && getSourceValue() && !expanded\">\u2713</span>\n </div>\n <div class=\"field-array-content\" *ngIf=\"expanded\">\n <!-- Source collection input -->\n <div class=\"field-row\">\n <div class=\"field-label\">\n <span class=\"field-name\">{{ 'mapCollectionTo' | pluginTranslate: pluginId | async }}</span>\n </div>\n <div class=\"field-input\">\n <div class=\"input-mode-group\">\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'browse'\" [disabled]=\"disabled\" (click)=\"setInputMode('browse')\" [title]=\"'browseMode' | pluginTranslate: pluginId | async\">\u229E</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'pv'\" [disabled]=\"disabled\" (click)=\"setInputMode('pv')\" [title]=\"'pvMode' | pluginTranslate: pluginId | async\">pv</button>\n <button type=\"button\" class=\"mode-btn\" [class.mode-active]=\"inputMode === 'expression'\" [disabled]=\"disabled\" (click)=\"setInputMode('expression')\" [title]=\"'expressionMode' | pluginTranslate: pluginId | async\">fx</button>\n </div>\n\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'browse'\">\n <valtimo-value-path-selector\n [name]=\"'field_' + field.path\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [prefixes]=\"[ValuePathSelectorPrefix.DOC, ValuePathSelectorPrefix.CASE]\"\n [notation]=\"'dots'\"\n [disabled]=\"disabled\"\n [defaultValue]=\"getSourceValue()\"\n [showCaseDefinitionSelector]=\"!caseDefinitionKey\"\n (valueChangeEvent)=\"onSourceBrowseChange($event)\"\n ></valtimo-value-path-selector>\n </div>\n\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'pv'\">\n <select\n *ngIf=\"processVariables.length > 0; else pvSourceFallback\"\n class=\"pv-select\"\n [disabled]=\"disabled\"\n (change)=\"onSourcePvChange($any($event.target).value)\"\n >\n <option value=\"\">{{ 'pvPlaceholder' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let pv of processVariables\" [value]=\"pv\" [selected]=\"pv === getSourcePvName()\">{{ pv }}</option>\n </select>\n <ng-template #pvSourceFallback>\n <v-input\n [name]=\"'pvfb_' + field.path\"\n [defaultValue]=\"getSourcePvName()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'pvPlaceholder' | pluginTranslate: pluginId | async\"\n (valueChange)=\"onSourcePvChange($event)\"\n ></v-input>\n </ng-template>\n </div>\n\n <div class=\"field-input-control\" *ngIf=\"inputMode === 'expression'\">\n <v-input\n [name]=\"'fx_' + field.path\"\n [defaultValue]=\"getSourceValue()\"\n [disabled]=\"disabled\"\n [placeholder]=\"'e.g. pv:variableName or doc:path.to.field'\"\n (valueChange)=\"onSourceExpressionChange($event)\"\n ></v-input>\n </div>\n </div>\n </div>\n\n <!-- Per-item field mapping toggle (only shown when array has children) -->\n <div class=\"array-per-field-toggle\" *ngIf=\"hasArrayChildren()\">\n <label class=\"toggle-label\">\n <input\n type=\"checkbox\"\n [checked]=\"arrayPerFieldMode\"\n [disabled]=\"disabled\"\n (change)=\"toggleArrayPerFieldMode()\"\n />\n <span>{{ 'itemFieldMapping' | pluginTranslate: pluginId | async }}</span>\n </label>\n </div>\n\n <!-- Per-item field mappings -->\n <div class=\"array-item-fields\" *ngIf=\"arrayPerFieldMode && hasArrayChildren()\">\n <div class=\"item-fields-header\">\n <span class=\"item-fields-title\">{{ 'itemFieldMappingTitle' | pluginTranslate: pluginId | async }}</span>\n </div>\n <div class=\"item-field-row\" *ngFor=\"let child of field.children\">\n <div class=\"item-field-label\">\n <span class=\"field-name\">{{ child.name }}</span>\n <span class=\"field-meta\">({{ child.type }}{{ child.required ? ', required' : '' }})</span>\n </div>\n <div class=\"item-field-input\">\n <v-input\n [name]=\"'itemField_' + child.path\"\n [defaultValue]=\"getItemFieldValue(child.name)\"\n [disabled]=\"disabled\"\n [placeholder]=\"'sourceFieldPlaceholder' | pluginTranslate: pluginId | async\"\n (valueChange)=\"onItemFieldChange(child.name, $event)\"\n ></v-input>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".field-row{display:flex;align-items:flex-start;gap:.75rem;padding:.5rem 0;border-left:3px solid transparent}.field-row.field-required-unmapped{border-left-color:#dc3545;background-color:#fff5f5;padding-left:.5rem}.field-label{flex:0 0 200px;min-width:140px;padding-top:.5rem;word-break:break-word}.field-label .field-name{font-weight:500}.field-label .field-meta{font-size:.8125rem;color:#6c757d;margin-left:.25rem}.field-input{flex:1;display:flex;align-items:flex-start;gap:.5rem;min-width:0}.field-input-control{flex:1;min-width:0}.input-mode-group{flex:0 0 auto;display:flex;margin-top:.25rem;border:1px solid #c6c6c6;border-radius:4px;overflow:hidden}.input-mode-group .mode-btn{width:32px;height:32px;padding:0;border:none;border-right:1px solid #c6c6c6;background:#f4f4f4;color:#525252;font-size:.75rem;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color .15s}.input-mode-group .mode-btn:last-child{border-right:none}.input-mode-group .mode-btn:hover:not(:disabled){background:#e0e0e0}.input-mode-group .mode-btn.mode-active{background:#0f62fe;color:#fff}.input-mode-group .mode-btn.mode-active:hover:not(:disabled){background:#0353e9}.input-mode-group .mode-btn:disabled{opacity:.5;cursor:not-allowed}.pv-select{width:100%;height:2.5rem;padding:0 .75rem;border:1px solid #c6c6c6;border-radius:4px;background:#fff;color:#161616;font-size:.875rem;cursor:pointer}.pv-select:focus{outline:2px solid #0f62fe;outline-offset:-2px}.pv-select:disabled{opacity:.5;cursor:not-allowed;background:#f4f4f4}.field-object{margin:.25rem 0}.field-object-header,.field-array-header{display:flex;align-items:center;gap:.5rem;padding:.5rem .25rem;cursor:pointer;-webkit-user-select:none;user-select:none;border-left:3px solid transparent;border-radius:2px}.field-object-header:hover,.field-array-header:hover{background:#f4f4f4}.field-object-header.field-required-unmapped,.field-array-header.field-required-unmapped{border-left-color:#dc3545;background-color:#fff5f5}.field-object-header .expand-icon,.field-array-header .expand-icon{flex:0 0 1rem;font-size:.75rem;color:#525252}.field-object-header .field-name,.field-array-header .field-name{font-weight:500}.field-object-header .field-meta,.field-array-header .field-meta{font-size:.8125rem;color:#6c757d}.field-object-header .completeness-badge,.field-array-header .completeness-badge{margin-left:auto;font-size:.75rem;padding:.125rem .5rem;border-radius:10px;background:#e0e0e0;color:#525252;font-weight:500}.field-object-header .mapped-indicator,.field-array-header .mapped-indicator{margin-left:auto;color:#198754;font-weight:600}.field-object-children{padding-left:1.25rem;border-left:1px solid #e0e0e0;margin-left:.5rem}.field-array{margin:.25rem 0}.field-array-content{padding-left:1.25rem;border-left:1px solid #e0e0e0;margin-left:.5rem}.array-per-field-toggle{padding:.5rem 0}.array-per-field-toggle .toggle-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem;color:#525252}.array-per-field-toggle .toggle-label input[type=checkbox]{cursor:pointer}.array-item-fields{margin-left:.5rem;border-left:1px dashed #c6c6c6;padding:.25rem 0 .5rem 1rem}.item-fields-header{padding-bottom:.25rem}.item-fields-header .item-fields-title{font-size:.8125rem;font-weight:500;color:#6c757d}.item-field-row{display:flex;align-items:center;gap:.75rem;padding:.25rem 0}.item-field-label{flex:0 0 180px;min-width:120px;word-break:break-word}.item-field-label .field-name{font-weight:500;font-size:.875rem}.item-field-label .field-meta{font-size:.75rem;color:#6c757d;margin-left:.25rem}.item-field-input{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: FieldTreeComponent, selector: "epistola-field-tree", inputs: ["field", "value", "pluginId", "caseDefinitionKey", "processVariables", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }, { kind: "component", type: ValuePathSelectorComponent, selector: "valtimo-value-path-selector", inputs: ["name", "appendInline", "margin", "marginLg", "marginXl", "disabled", "caseDefinitionKey", "caseDefinitionVersionTag", "buildingBlockDefinitionKey", "buildingBlockDefinitionVersionTag", "prefixes", "label", "tooltip", "required", "showCaseDefinitionSelector", "notation", "dropUp", "defaultValue", "type", "parentItem", "filterItems"], outputs: ["valueChangeEvent", "collectionSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
430
460
  }
431
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FieldTreeComponent, decorators: [{
461
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FieldTreeComponent, decorators: [{
432
462
  type: Component,
433
- args: [{ selector: 'epistola-field-tree', standalone: true, imports: [
463
+ args: [{ selector: 'epistola-field-tree', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
434
464
  CommonModule,
435
465
  FormsModule,
436
466
  PluginTranslatePipeModule,
@@ -504,49 +534,15 @@ class DataMappingTreeComponent {
504
534
  return this.mapping[fieldName];
505
535
  }
506
536
  emitRequiredFieldsStatus() {
507
- const stats = this.countRequiredMapped(this.templateFields, this.mapping);
537
+ const stats = countRequiredMapped(this.templateFields, this.mapping);
508
538
  this.requiredFieldsStatus.emit(stats);
509
539
  }
510
- countRequiredMapped(fields, mapping) {
511
- let mapped = 0;
512
- let total = 0;
513
- for (const field of fields) {
514
- if (field.fieldType === 'SCALAR' && field.required) {
515
- total++;
516
- const val = mapping[field.name];
517
- if (typeof val === 'string' && val.trim().length > 0) {
518
- mapped++;
519
- }
520
- }
521
- else if (field.fieldType === 'ARRAY' && field.required) {
522
- total++;
523
- const val = mapping[field.name];
524
- if (typeof val === 'string' && val.trim().length > 0) {
525
- mapped++;
526
- }
527
- else if (typeof val === 'object' && val !== null && '_source' in val) {
528
- if (typeof val['_source'] === 'string' && val['_source'].trim().length > 0) {
529
- mapped++;
530
- }
531
- }
532
- }
533
- else if (field.fieldType === 'OBJECT' && field.children) {
534
- const nested = (typeof mapping[field.name] === 'object' && mapping[field.name] !== null)
535
- ? mapping[field.name]
536
- : {};
537
- const childStats = this.countRequiredMapped(field.children, nested);
538
- mapped += childStats.mapped;
539
- total += childStats.total;
540
- }
541
- }
542
- return { mapped, total };
543
- }
544
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DataMappingTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
545
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: DataMappingTreeComponent, isStandalone: true, selector: "epistola-data-mapping-tree", inputs: { pluginId: "pluginId", templateFields$: "templateFields$", prefillMapping$: "prefillMapping$", disabled$: "disabled$", caseDefinitionKey: "caseDefinitionKey", processVariables: "processVariables" }, outputs: { mappingChange: "mappingChange", requiredFieldsStatus: "requiredFieldsStatus" }, ngImport: i0, template: "<div class=\"data-mapping-tree\">\n <div class=\"mapping-header\">\n <h5>{{ 'dataMappingTitle' | pluginTranslate: pluginId | async }}</h5>\n <p class=\"helper-text\">{{ 'dataMappingDescription' | pluginTranslate: pluginId | async }}</p>\n </div>\n\n <div class=\"field-tree-root\" *ngIf=\"templateFields.length > 0\">\n <epistola-field-tree\n *ngFor=\"let field of templateFields\"\n [field]=\"field\"\n [value]=\"getFieldValue(field.name)\"\n [pluginId]=\"pluginId\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n [disabled]=\"disabled\"\n (valueChange)=\"onFieldValueChange(field.name, $event)\"\n ></epistola-field-tree>\n </div>\n\n <div class=\"no-fields\" *ngIf=\"templateFields.length === 0\">\n <p>{{ 'noTemplateFields' | pluginTranslate: pluginId | async }}</p>\n </div>\n</div>\n", styles: [".data-mapping-tree{margin-top:1rem;margin-bottom:1rem}.mapping-header{margin-bottom:.75rem}.mapping-header h5{margin-bottom:.25rem;font-weight:600}.mapping-header .helper-text{color:#6c757d;font-size:.875rem;margin-bottom:0}.field-tree-root{border:1px solid #e0e0e0;border-radius:4px;padding:.5rem .75rem}.no-fields{padding:1rem;text-align:center;color:#6c757d;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:4px}.no-fields p{margin-bottom:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "component", type: FieldTreeComponent, selector: "epistola-field-tree", inputs: ["field", "value", "pluginId", "caseDefinitionKey", "processVariables", "disabled"], outputs: ["valueChange"] }] });
540
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DataMappingTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
541
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: DataMappingTreeComponent, isStandalone: true, selector: "epistola-data-mapping-tree", inputs: { pluginId: "pluginId", templateFields$: "templateFields$", prefillMapping$: "prefillMapping$", disabled$: "disabled$", caseDefinitionKey: "caseDefinitionKey", processVariables: "processVariables" }, outputs: { mappingChange: "mappingChange", requiredFieldsStatus: "requiredFieldsStatus" }, ngImport: i0, template: "<div class=\"data-mapping-tree\">\n <div class=\"mapping-header\">\n <h5>{{ 'dataMappingTitle' | pluginTranslate: pluginId | async }}</h5>\n <p class=\"helper-text\">{{ 'dataMappingDescription' | pluginTranslate: pluginId | async }}</p>\n </div>\n\n <div class=\"field-tree-root\" *ngIf=\"templateFields.length > 0\">\n <epistola-field-tree\n *ngFor=\"let field of templateFields\"\n [field]=\"field\"\n [value]=\"getFieldValue(field.name)\"\n [pluginId]=\"pluginId\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n [disabled]=\"disabled\"\n (valueChange)=\"onFieldValueChange(field.name, $event)\"\n ></epistola-field-tree>\n </div>\n\n <div class=\"no-fields\" *ngIf=\"templateFields.length === 0\">\n <p>{{ 'noTemplateFields' | pluginTranslate: pluginId | async }}</p>\n </div>\n</div>\n", styles: [".data-mapping-tree{margin-top:1rem;margin-bottom:1rem}.mapping-header{margin-bottom:.75rem}.mapping-header h5{margin-bottom:.25rem;font-weight:600}.mapping-header .helper-text{color:#6c757d;font-size:.875rem;margin-bottom:0}.field-tree-root{border:1px solid #e0e0e0;border-radius:4px;padding:.5rem .75rem}.no-fields{padding:1rem;text-align:center;color:#6c757d;background-color:#f8f9fa;border:1px solid #dee2e6;border-radius:4px}.no-fields p{margin-bottom:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "component", type: FieldTreeComponent, selector: "epistola-field-tree", inputs: ["field", "value", "pluginId", "caseDefinitionKey", "processVariables", "disabled"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
546
542
  }
547
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DataMappingTreeComponent, decorators: [{
543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DataMappingTreeComponent, decorators: [{
548
544
  type: Component,
549
- args: [{ selector: 'epistola-data-mapping-tree', standalone: true, imports: [
545
+ args: [{ selector: 'epistola-data-mapping-tree', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
550
546
  CommonModule,
551
547
  PluginTranslatePipeModule,
552
548
  FieldTreeComponent
@@ -572,6 +568,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
572
568
  class GenerateDocumentConfigurationComponent {
573
569
  epistolaPluginService;
574
570
  processLinkStateService;
571
+ cdr;
575
572
  // Required inputs from FunctionConfigurationComponent
576
573
  save$;
577
574
  disabled$;
@@ -585,15 +582,19 @@ class GenerateDocumentConfigurationComponent {
585
582
  // Template options loaded from API
586
583
  templateOptions$ = new BehaviorSubject([]);
587
584
  templatesLoading$ = new BehaviorSubject(false);
585
+ templatesError$ = new BehaviorSubject(null);
588
586
  // Variant options loaded based on selected template
589
587
  variantOptions$ = new BehaviorSubject([]);
590
588
  variantsLoading$ = new BehaviorSubject(false);
589
+ variantsError$ = new BehaviorSubject(null);
591
590
  // Environment options loaded from API
592
591
  environmentOptions$ = new BehaviorSubject([]);
593
592
  environmentsLoading$ = new BehaviorSubject(false);
593
+ environmentsError$ = new BehaviorSubject(null);
594
594
  // Template fields for data mapping
595
595
  templateFields$ = new BehaviorSubject([]);
596
596
  templateFieldsLoading$ = new BehaviorSubject(false);
597
+ templateFieldsError$ = new BehaviorSubject(null);
597
598
  // Current data mapping (nested structure mirroring template schema)
598
599
  dataMapping$ = new BehaviorSubject({});
599
600
  // Prefill data mapping observable for the tree
@@ -620,9 +621,10 @@ class GenerateDocumentConfigurationComponent {
620
621
  formValue$ = new BehaviorSubject(null);
621
622
  valid$ = new BehaviorSubject(false);
622
623
  pluginConfigurationId$ = new BehaviorSubject('');
623
- constructor(epistolaPluginService, processLinkStateService) {
624
+ constructor(epistolaPluginService, processLinkStateService, cdr) {
624
625
  this.epistolaPluginService = epistolaPluginService;
625
626
  this.processLinkStateService = processLinkStateService;
627
+ this.cdr = cdr;
626
628
  }
627
629
  ngOnInit() {
628
630
  this.initContext();
@@ -707,6 +709,7 @@ class GenerateDocumentConfigurationComponent {
707
709
  if (this.context$) {
708
710
  this.context$.pipe(takeUntil(this.destroy$), filter(([context]) => context === 'case')).subscribe(([, params]) => {
709
711
  this.caseDefinitionKey = params.caseDefinitionKey;
712
+ this.cdr.markForCheck();
710
713
  });
711
714
  }
712
715
  }
@@ -728,6 +731,7 @@ class GenerateDocumentConfigurationComponent {
728
731
  if (config.dataMapping) {
729
732
  this.dataMapping$.next(config.dataMapping);
730
733
  }
734
+ this.cdr.markForCheck();
731
735
  });
732
736
  }
733
737
  else {
@@ -750,7 +754,11 @@ class GenerateDocumentConfigurationComponent {
750
754
  initTemplatesLoading() {
751
755
  this.pluginConfigurationId$.pipe(takeUntil(this.destroy$), filter(id => !!id)).subscribe(configurationId => {
752
756
  this.templatesLoading$.next(true);
753
- this.epistolaPluginService.getTemplates(configurationId).pipe(takeUntil(this.destroy$), catchError(() => of([]))).subscribe(templates => {
757
+ this.templatesError$.next(null);
758
+ this.epistolaPluginService.getTemplates(configurationId).pipe(takeUntil(this.destroy$), catchError(() => {
759
+ this.templatesError$.next('Failed to load templates');
760
+ return of([]);
761
+ })).subscribe(templates => {
754
762
  const options = templates.map(t => ({
755
763
  id: t.id,
756
764
  text: t.name
@@ -763,7 +771,11 @@ class GenerateDocumentConfigurationComponent {
763
771
  initEnvironmentsLoading() {
764
772
  this.pluginConfigurationId$.pipe(takeUntil(this.destroy$), filter(id => !!id)).subscribe(configurationId => {
765
773
  this.environmentsLoading$.next(true);
766
- this.epistolaPluginService.getEnvironments(configurationId).pipe(takeUntil(this.destroy$), catchError(() => of([]))).subscribe(environments => {
774
+ this.environmentsError$.next(null);
775
+ this.epistolaPluginService.getEnvironments(configurationId).pipe(takeUntil(this.destroy$), catchError(() => {
776
+ this.environmentsError$.next('Failed to load environments');
777
+ return of([]);
778
+ })).subscribe(environments => {
767
779
  const options = environments.map(e => ({
768
780
  id: e.id,
769
781
  text: e.name
@@ -779,7 +791,11 @@ class GenerateDocumentConfigurationComponent {
779
791
  this.selectedTemplateId$
780
792
  ]).pipe(takeUntil(this.destroy$), filter(([configId, templateId]) => !!configId && !!templateId)).subscribe(([configurationId, templateId]) => {
781
793
  this.variantsLoading$.next(true);
782
- this.epistolaPluginService.getVariants(configurationId, templateId).pipe(takeUntil(this.destroy$), catchError(() => of([]))).subscribe(variants => {
794
+ this.variantsError$.next(null);
795
+ this.epistolaPluginService.getVariants(configurationId, templateId).pipe(takeUntil(this.destroy$), catchError(() => {
796
+ this.variantsError$.next('Failed to load variants');
797
+ return of([]);
798
+ })).subscribe(variants => {
783
799
  const options = variants.map(v => ({
784
800
  id: v.id,
785
801
  text: v.name + this.formatAttributes(v.attributes)
@@ -795,7 +811,11 @@ class GenerateDocumentConfigurationComponent {
795
811
  this.selectedTemplateId$
796
812
  ]).pipe(takeUntil(this.destroy$), filter(([configId, templateId]) => !!configId && !!templateId)).subscribe(([configurationId, templateId]) => {
797
813
  this.templateFieldsLoading$.next(true);
798
- this.epistolaPluginService.getTemplateDetails(configurationId, templateId).pipe(takeUntil(this.destroy$), catchError(() => of({ fields: [] }))).subscribe(details => {
814
+ this.templateFieldsError$.next(null);
815
+ this.epistolaPluginService.getTemplateDetails(configurationId, templateId).pipe(takeUntil(this.destroy$), catchError(() => {
816
+ this.templateFieldsError$.next('Failed to load template fields');
817
+ return of({ fields: [] });
818
+ })).subscribe(details => {
799
819
  this.templateFields$.next(details.fields || []);
800
820
  this.templateFieldsLoading$.next(false);
801
821
  });
@@ -808,6 +828,7 @@ class GenerateDocumentConfigurationComponent {
808
828
  if (this.caseDefinitionKey) {
809
829
  this.epistolaPluginService.getProcessVariables(this.caseDefinitionKey).pipe(takeUntil(this.destroy$), catchError(() => of([]))).subscribe(variables => {
810
830
  this.processVariables = variables;
831
+ this.cdr.markForCheck();
811
832
  });
812
833
  }
813
834
  }
@@ -860,12 +881,12 @@ class GenerateDocumentConfigurationComponent {
860
881
  });
861
882
  });
862
883
  }
863
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: GenerateDocumentConfigurationComponent, deps: [{ token: EpistolaPluginService }, { token: i2$2.ProcessLinkStateService }], target: i0.ɵɵFactoryTarget.Component });
864
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: GenerateDocumentConfigurationComponent, isStandalone: true, selector: "epistola-generate-document-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$", selectedPluginConfigurationData$: "selectedPluginConfigurationData$", context$: "context$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: disabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null,\n templateOptions: templateOptions$ | async,\n templatesLoading: templatesLoading$ | async,\n variantOptions: variantOptions$ | async,\n variantsLoading: variantsLoading$ | async,\n environmentOptions: environmentOptions$ | async,\n environmentsLoading: environmentsLoading$ | async,\n templateFieldsLoading: templateFieldsLoading$ | async,\n selectedTemplateId: selectedTemplateId$ | async\n } as obs\"\n>\n <v-select\n name=\"templateId\"\n [title]=\"'templateId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'templateIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.templateOptions\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templatesLoading\"\n [required]=\"true\"\n [loading]=\"obs.templatesLoading\"\n >\n </v-select>\n\n <!-- Variant selection mode toggle -->\n <div class=\"variant-mode-toggle\" *ngIf=\"obs.selectedTemplateId\">\n <label class=\"variant-mode-label\">{{ 'variantSelectionMode' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-mode-buttons\">\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'explicit'\"\n (click)=\"onVariantSelectionModeChange('explicit')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByVariant' | pluginTranslate: pluginId | async }}</button>\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'attributes'\"\n (click)=\"onVariantSelectionModeChange('attributes')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByAttributes' | pluginTranslate: pluginId | async }}</button>\n </div>\n </div>\n\n <!-- Explicit variant selection (dropdown) -->\n <v-select\n *ngIf=\"variantSelectionMode === 'explicit'\"\n name=\"variantId\"\n [title]=\"'variantId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'variantIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.variantOptions\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variantsLoading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variantsLoading\"\n >\n </v-select>\n\n <!-- Attribute-based variant selection -->\n <div *ngIf=\"variantSelectionMode === 'attributes' && obs.selectedTemplateId\" class=\"variant-attributes-section\">\n <label class=\"variant-attributes-label\">{{ 'variantAttributes' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-attributes-list\">\n <div *ngFor=\"let entry of variantAttributeEntries; let i = index\" class=\"variant-attribute-row\">\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeKey' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.key\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeValue' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.value\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <button\n type=\"button\"\n class=\"variant-attribute-remove-btn\"\n (click)=\"removeAttributeEntry(i)\"\n [disabled]=\"obs.disabled\"\n title=\"{{ 'removeAttribute' | pluginTranslate: pluginId | async }}\"\n >&times;</button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"variant-attribute-add-btn\"\n (click)=\"addAttributeEntry()\"\n [disabled]=\"obs.disabled\"\n >+ {{ 'addAttribute' | pluginTranslate: pluginId | async }}</button>\n </div>\n\n <v-select\n name=\"environmentId\"\n [title]=\"'environmentId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'environmentIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.environmentOptions\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environmentsLoading\"\n [required]=\"false\"\n [loading]=\"obs.environmentsLoading\"\n >\n </v-select>\n\n <v-select\n name=\"outputFormat\"\n [title]=\"'outputFormat' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'outputFormatTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"outputFormatOptions\"\n [defaultSelectionId]=\"obs.prefill?.outputFormat || 'PDF'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-select>\n\n <v-input\n name=\"filename\"\n [title]=\"'filename' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'filenameTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.filename\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"correlationId\"\n [title]=\"'correlationId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'correlationIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.correlationId\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"resultProcessVariable\"\n [title]=\"'resultProcessVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'resultProcessVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.resultProcessVariable\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n</v-form>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields$]=\"templateFields$\"\n [disabled$]=\"disabled$\"\n [prefillMapping$]=\"prefillDataMapping$\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n (mappingChange)=\"onDataMappingChange($event)\"\n (requiredFieldsStatus)=\"onRequiredFieldsStatusChange($event)\"\n></epistola-data-mapping-tree>\n\n<div class=\"validation-summary\" *ngIf=\"(selectedTemplateId$ | async) && requiredFieldsStatus.total > 0\">\n <span *ngIf=\"requiredFieldsStatus.mapped === requiredFieldsStatus.total\" class=\"validation-complete\">\n {{ 'requiredFieldsComplete' | pluginTranslate: pluginId | async }}\n </span>\n <span *ngIf=\"requiredFieldsStatus.mapped < requiredFieldsStatus.total\" class=\"validation-incomplete\">\n {{ requiredFieldsStatus.mapped }} / {{ requiredFieldsStatus.total }}\n {{ 'validationSummary' | pluginTranslate: pluginId | async }}\n </span>\n</div>\n", styles: [".validation-summary{margin-top:.5rem;padding:.5rem .75rem;border-radius:4px;font-size:.875rem}.validation-summary .validation-complete{color:#198754}.validation-summary .validation-incomplete{color:#dc3545;font-weight:500}.variant-mode-toggle{margin-bottom:1rem;padding:0 .75rem}.variant-mode-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-mode-buttons{display:flex;gap:0;border:1px solid #d1d5db;border-radius:4px;overflow:hidden;width:fit-content}.variant-mode-btn{padding:.375rem .75rem;font-size:.8125rem;background:#fff;border:none;border-right:1px solid #d1d5db;cursor:pointer;color:#374151;transition:background-color .15s,color .15s}.variant-mode-btn:last-child{border-right:none}.variant-mode-btn:hover:not([disabled]){background:#f3f4f6}.variant-mode-btn.active{background:#2563eb;color:#fff}.variant-mode-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attributes-section{margin-bottom:1rem;padding:0 .75rem}.variant-attributes-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-attributes-list{display:flex;flex-direction:column;gap:.375rem}.variant-attribute-row{display:flex;gap:.375rem;align-items:center}.variant-attribute-input{flex:1;padding:.375rem .5rem;font-size:.8125rem;border:1px solid #d1d5db;border-radius:4px;outline:none}.variant-attribute-input:focus{border-color:#2563eb;box-shadow:0 0 0 1px #2563eb}.variant-attribute-input[disabled]{opacity:.5;background:#f9fafb}.variant-attribute-remove-btn{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-remove-btn:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.variant-attribute-remove-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-add-btn{margin-top:.375rem;padding:.25rem .5rem;font-size:.8125rem;background:none;border:1px dashed #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-add-btn:hover:not([disabled]){color:#2563eb;border-color:#2563eb}.variant-attribute-add-btn[disabled]{opacity:.5;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3.SelectComponent, selector: "v-select", inputs: ["items", "defaultSelection", "defaultSelectionId", "defaultSelectionIds", "disabled", "dropUp", "invalid", "multiple", "margin", "widthInPx", "notFoundText", "clearAllText", "clearText", "clearable", "name", "title", "titleTranslationKey", "clearSelectionSubject$", "tooltip", "required", "loading", "loadingText", "placeholder", "smallMargin", "carbonTheme", "appendInline", "dataTestId"], outputs: ["selectedChange"] }, { kind: "component", type: DataMappingTreeComponent, selector: "epistola-data-mapping-tree", inputs: ["pluginId", "templateFields$", "prefillMapping$", "disabled$", "caseDefinitionKey", "processVariables"], outputs: ["mappingChange", "requiredFieldsStatus"] }] });
884
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GenerateDocumentConfigurationComponent, deps: [{ token: EpistolaPluginService }, { token: i2$2.ProcessLinkStateService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
885
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: GenerateDocumentConfigurationComponent, isStandalone: true, selector: "epistola-generate-document-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$", selectedPluginConfigurationData$: "selectedPluginConfigurationData$", context$: "context$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: disabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null,\n templateOptions: templateOptions$ | async,\n templatesLoading: templatesLoading$ | async,\n templatesError: templatesError$ | async,\n variantOptions: variantOptions$ | async,\n variantsLoading: variantsLoading$ | async,\n variantsError: variantsError$ | async,\n environmentOptions: environmentOptions$ | async,\n environmentsLoading: environmentsLoading$ | async,\n environmentsError: environmentsError$ | async,\n templateFieldsLoading: templateFieldsLoading$ | async,\n selectedTemplateId: selectedTemplateId$ | async\n } as obs\"\n>\n <v-select\n name=\"templateId\"\n [title]=\"'templateId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'templateIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.templateOptions\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templatesLoading\"\n [required]=\"true\"\n [loading]=\"obs.templatesLoading\"\n >\n </v-select>\n <div *ngIf=\"obs.templatesError\" class=\"loading-error\">{{ obs.templatesError }}</div>\n\n <!-- Variant selection mode toggle -->\n <div class=\"variant-mode-toggle\" *ngIf=\"obs.selectedTemplateId\">\n <label class=\"variant-mode-label\">{{ 'variantSelectionMode' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-mode-buttons\">\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'explicit'\"\n (click)=\"onVariantSelectionModeChange('explicit')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByVariant' | pluginTranslate: pluginId | async }}</button>\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'attributes'\"\n (click)=\"onVariantSelectionModeChange('attributes')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByAttributes' | pluginTranslate: pluginId | async }}</button>\n </div>\n </div>\n\n <!-- Explicit variant selection (dropdown) -->\n <v-select\n *ngIf=\"variantSelectionMode === 'explicit'\"\n name=\"variantId\"\n [title]=\"'variantId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'variantIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.variantOptions\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variantsLoading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variantsLoading\"\n >\n </v-select>\n <div *ngIf=\"obs.variantsError\" class=\"loading-error\">{{ obs.variantsError }}</div>\n\n <!-- Attribute-based variant selection -->\n <div *ngIf=\"variantSelectionMode === 'attributes' && obs.selectedTemplateId\" class=\"variant-attributes-section\">\n <label class=\"variant-attributes-label\">{{ 'variantAttributes' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-attributes-list\">\n <div *ngFor=\"let entry of variantAttributeEntries; let i = index\" class=\"variant-attribute-row\">\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeKey' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.key\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeValue' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.value\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <button\n type=\"button\"\n class=\"variant-attribute-remove-btn\"\n (click)=\"removeAttributeEntry(i)\"\n [disabled]=\"obs.disabled\"\n title=\"{{ 'removeAttribute' | pluginTranslate: pluginId | async }}\"\n >&times;</button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"variant-attribute-add-btn\"\n (click)=\"addAttributeEntry()\"\n [disabled]=\"obs.disabled\"\n >+ {{ 'addAttribute' | pluginTranslate: pluginId | async }}</button>\n </div>\n\n <v-select\n name=\"environmentId\"\n [title]=\"'environmentId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'environmentIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.environmentOptions\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environmentsLoading\"\n [required]=\"false\"\n [loading]=\"obs.environmentsLoading\"\n >\n </v-select>\n <div *ngIf=\"obs.environmentsError\" class=\"loading-error\">{{ obs.environmentsError }}</div>\n\n <v-select\n name=\"outputFormat\"\n [title]=\"'outputFormat' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'outputFormatTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"outputFormatOptions\"\n [defaultSelectionId]=\"obs.prefill?.outputFormat || 'PDF'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-select>\n\n <v-input\n name=\"filename\"\n [title]=\"'filename' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'filenameTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.filename\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"correlationId\"\n [title]=\"'correlationId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'correlationIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.correlationId\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"resultProcessVariable\"\n [title]=\"'resultProcessVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'resultProcessVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.resultProcessVariable\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n</v-form>\n\n<div *ngIf=\"templateFieldsError$ | async as templateFieldsError\" class=\"loading-error\">{{ templateFieldsError }}</div>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields$]=\"templateFields$\"\n [disabled$]=\"disabled$\"\n [prefillMapping$]=\"prefillDataMapping$\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n (mappingChange)=\"onDataMappingChange($event)\"\n (requiredFieldsStatus)=\"onRequiredFieldsStatusChange($event)\"\n></epistola-data-mapping-tree>\n\n<div class=\"validation-summary\" *ngIf=\"(selectedTemplateId$ | async) && requiredFieldsStatus.total > 0\">\n <span *ngIf=\"requiredFieldsStatus.mapped === requiredFieldsStatus.total\" class=\"validation-complete\">\n {{ 'requiredFieldsComplete' | pluginTranslate: pluginId | async }}\n </span>\n <span *ngIf=\"requiredFieldsStatus.mapped < requiredFieldsStatus.total\" class=\"validation-incomplete\">\n {{ requiredFieldsStatus.mapped }} / {{ requiredFieldsStatus.total }}\n {{ 'validationSummary' | pluginTranslate: pluginId | async }}\n </span>\n</div>\n", styles: [".loading-error{padding:.25rem .75rem;font-size:.8125rem;color:#dc3545}.validation-summary{margin-top:.5rem;padding:.5rem .75rem;border-radius:4px;font-size:.875rem}.validation-summary .validation-complete{color:#198754}.validation-summary .validation-incomplete{color:#dc3545;font-weight:500}.variant-mode-toggle{margin-bottom:1rem;padding:0 .75rem}.variant-mode-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-mode-buttons{display:flex;gap:0;border:1px solid #d1d5db;border-radius:4px;overflow:hidden;width:fit-content}.variant-mode-btn{padding:.375rem .75rem;font-size:.8125rem;background:#fff;border:none;border-right:1px solid #d1d5db;cursor:pointer;color:#374151;transition:background-color .15s,color .15s}.variant-mode-btn:last-child{border-right:none}.variant-mode-btn:hover:not([disabled]){background:#f3f4f6}.variant-mode-btn.active{background:#2563eb;color:#fff}.variant-mode-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attributes-section{margin-bottom:1rem;padding:0 .75rem}.variant-attributes-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-attributes-list{display:flex;flex-direction:column;gap:.375rem}.variant-attribute-row{display:flex;gap:.375rem;align-items:center}.variant-attribute-input{flex:1;padding:.375rem .5rem;font-size:.8125rem;border:1px solid #d1d5db;border-radius:4px;outline:none}.variant-attribute-input:focus{border-color:#2563eb;box-shadow:0 0 0 1px #2563eb}.variant-attribute-input[disabled]{opacity:.5;background:#f9fafb}.variant-attribute-remove-btn{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-remove-btn:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.variant-attribute-remove-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-add-btn{margin-top:.375rem;padding:.25rem .5rem;font-size:.8125rem;background:none;border:1px dashed #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-add-btn:hover:not([disabled]){color:#2563eb;border-color:#2563eb}.variant-attribute-add-btn[disabled]{opacity:.5;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3.SelectComponent, selector: "v-select", inputs: ["items", "defaultSelection", "defaultSelectionId", "defaultSelectionIds", "disabled", "dropUp", "invalid", "multiple", "margin", "widthInPx", "notFoundText", "clearAllText", "clearText", "clearable", "name", "title", "titleTranslationKey", "clearSelectionSubject$", "tooltip", "required", "loading", "loadingText", "placeholder", "smallMargin", "carbonTheme", "appendInline", "warn", "warnText", "dataTestId"], outputs: ["selectedChange"] }, { kind: "component", type: DataMappingTreeComponent, selector: "epistola-data-mapping-tree", inputs: ["pluginId", "templateFields$", "prefillMapping$", "disabled$", "caseDefinitionKey", "processVariables"], outputs: ["mappingChange", "requiredFieldsStatus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
865
886
  }
866
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: GenerateDocumentConfigurationComponent, decorators: [{
887
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GenerateDocumentConfigurationComponent, decorators: [{
867
888
  type: Component,
868
- args: [{ selector: 'epistola-generate-document-configuration', standalone: true, imports: [
889
+ args: [{ selector: 'epistola-generate-document-configuration', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
869
890
  CommonModule,
870
891
  FormsModule,
871
892
  PluginTranslatePipeModule,
@@ -873,8 +894,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
873
894
  InputModule,
874
895
  SelectModule,
875
896
  DataMappingTreeComponent
876
- ], template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: disabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null,\n templateOptions: templateOptions$ | async,\n templatesLoading: templatesLoading$ | async,\n variantOptions: variantOptions$ | async,\n variantsLoading: variantsLoading$ | async,\n environmentOptions: environmentOptions$ | async,\n environmentsLoading: environmentsLoading$ | async,\n templateFieldsLoading: templateFieldsLoading$ | async,\n selectedTemplateId: selectedTemplateId$ | async\n } as obs\"\n>\n <v-select\n name=\"templateId\"\n [title]=\"'templateId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'templateIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.templateOptions\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templatesLoading\"\n [required]=\"true\"\n [loading]=\"obs.templatesLoading\"\n >\n </v-select>\n\n <!-- Variant selection mode toggle -->\n <div class=\"variant-mode-toggle\" *ngIf=\"obs.selectedTemplateId\">\n <label class=\"variant-mode-label\">{{ 'variantSelectionMode' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-mode-buttons\">\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'explicit'\"\n (click)=\"onVariantSelectionModeChange('explicit')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByVariant' | pluginTranslate: pluginId | async }}</button>\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'attributes'\"\n (click)=\"onVariantSelectionModeChange('attributes')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByAttributes' | pluginTranslate: pluginId | async }}</button>\n </div>\n </div>\n\n <!-- Explicit variant selection (dropdown) -->\n <v-select\n *ngIf=\"variantSelectionMode === 'explicit'\"\n name=\"variantId\"\n [title]=\"'variantId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'variantIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.variantOptions\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variantsLoading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variantsLoading\"\n >\n </v-select>\n\n <!-- Attribute-based variant selection -->\n <div *ngIf=\"variantSelectionMode === 'attributes' && obs.selectedTemplateId\" class=\"variant-attributes-section\">\n <label class=\"variant-attributes-label\">{{ 'variantAttributes' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-attributes-list\">\n <div *ngFor=\"let entry of variantAttributeEntries; let i = index\" class=\"variant-attribute-row\">\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeKey' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.key\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeValue' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.value\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <button\n type=\"button\"\n class=\"variant-attribute-remove-btn\"\n (click)=\"removeAttributeEntry(i)\"\n [disabled]=\"obs.disabled\"\n title=\"{{ 'removeAttribute' | pluginTranslate: pluginId | async }}\"\n >&times;</button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"variant-attribute-add-btn\"\n (click)=\"addAttributeEntry()\"\n [disabled]=\"obs.disabled\"\n >+ {{ 'addAttribute' | pluginTranslate: pluginId | async }}</button>\n </div>\n\n <v-select\n name=\"environmentId\"\n [title]=\"'environmentId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'environmentIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.environmentOptions\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environmentsLoading\"\n [required]=\"false\"\n [loading]=\"obs.environmentsLoading\"\n >\n </v-select>\n\n <v-select\n name=\"outputFormat\"\n [title]=\"'outputFormat' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'outputFormatTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"outputFormatOptions\"\n [defaultSelectionId]=\"obs.prefill?.outputFormat || 'PDF'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-select>\n\n <v-input\n name=\"filename\"\n [title]=\"'filename' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'filenameTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.filename\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"correlationId\"\n [title]=\"'correlationId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'correlationIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.correlationId\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"resultProcessVariable\"\n [title]=\"'resultProcessVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'resultProcessVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.resultProcessVariable\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n</v-form>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields$]=\"templateFields$\"\n [disabled$]=\"disabled$\"\n [prefillMapping$]=\"prefillDataMapping$\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n (mappingChange)=\"onDataMappingChange($event)\"\n (requiredFieldsStatus)=\"onRequiredFieldsStatusChange($event)\"\n></epistola-data-mapping-tree>\n\n<div class=\"validation-summary\" *ngIf=\"(selectedTemplateId$ | async) && requiredFieldsStatus.total > 0\">\n <span *ngIf=\"requiredFieldsStatus.mapped === requiredFieldsStatus.total\" class=\"validation-complete\">\n {{ 'requiredFieldsComplete' | pluginTranslate: pluginId | async }}\n </span>\n <span *ngIf=\"requiredFieldsStatus.mapped < requiredFieldsStatus.total\" class=\"validation-incomplete\">\n {{ requiredFieldsStatus.mapped }} / {{ requiredFieldsStatus.total }}\n {{ 'validationSummary' | pluginTranslate: pluginId | async }}\n </span>\n</div>\n", styles: [".validation-summary{margin-top:.5rem;padding:.5rem .75rem;border-radius:4px;font-size:.875rem}.validation-summary .validation-complete{color:#198754}.validation-summary .validation-incomplete{color:#dc3545;font-weight:500}.variant-mode-toggle{margin-bottom:1rem;padding:0 .75rem}.variant-mode-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-mode-buttons{display:flex;gap:0;border:1px solid #d1d5db;border-radius:4px;overflow:hidden;width:fit-content}.variant-mode-btn{padding:.375rem .75rem;font-size:.8125rem;background:#fff;border:none;border-right:1px solid #d1d5db;cursor:pointer;color:#374151;transition:background-color .15s,color .15s}.variant-mode-btn:last-child{border-right:none}.variant-mode-btn:hover:not([disabled]){background:#f3f4f6}.variant-mode-btn.active{background:#2563eb;color:#fff}.variant-mode-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attributes-section{margin-bottom:1rem;padding:0 .75rem}.variant-attributes-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-attributes-list{display:flex;flex-direction:column;gap:.375rem}.variant-attribute-row{display:flex;gap:.375rem;align-items:center}.variant-attribute-input{flex:1;padding:.375rem .5rem;font-size:.8125rem;border:1px solid #d1d5db;border-radius:4px;outline:none}.variant-attribute-input:focus{border-color:#2563eb;box-shadow:0 0 0 1px #2563eb}.variant-attribute-input[disabled]{opacity:.5;background:#f9fafb}.variant-attribute-remove-btn{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-remove-btn:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.variant-attribute-remove-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-add-btn{margin-top:.375rem;padding:.25rem .5rem;font-size:.8125rem;background:none;border:1px dashed #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-add-btn:hover:not([disabled]){color:#2563eb;border-color:#2563eb}.variant-attribute-add-btn[disabled]{opacity:.5;cursor:not-allowed}\n"] }]
877
- }], ctorParameters: () => [{ type: EpistolaPluginService }, { type: i2$2.ProcessLinkStateService }], propDecorators: { save$: [{
897
+ ], template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: disabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null,\n templateOptions: templateOptions$ | async,\n templatesLoading: templatesLoading$ | async,\n templatesError: templatesError$ | async,\n variantOptions: variantOptions$ | async,\n variantsLoading: variantsLoading$ | async,\n variantsError: variantsError$ | async,\n environmentOptions: environmentOptions$ | async,\n environmentsLoading: environmentsLoading$ | async,\n environmentsError: environmentsError$ | async,\n templateFieldsLoading: templateFieldsLoading$ | async,\n selectedTemplateId: selectedTemplateId$ | async\n } as obs\"\n>\n <v-select\n name=\"templateId\"\n [title]=\"'templateId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'templateIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.templateOptions\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templatesLoading\"\n [required]=\"true\"\n [loading]=\"obs.templatesLoading\"\n >\n </v-select>\n <div *ngIf=\"obs.templatesError\" class=\"loading-error\">{{ obs.templatesError }}</div>\n\n <!-- Variant selection mode toggle -->\n <div class=\"variant-mode-toggle\" *ngIf=\"obs.selectedTemplateId\">\n <label class=\"variant-mode-label\">{{ 'variantSelectionMode' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-mode-buttons\">\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'explicit'\"\n (click)=\"onVariantSelectionModeChange('explicit')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByVariant' | pluginTranslate: pluginId | async }}</button>\n <button\n type=\"button\"\n class=\"variant-mode-btn\"\n [class.active]=\"variantSelectionMode === 'attributes'\"\n (click)=\"onVariantSelectionModeChange('attributes')\"\n [disabled]=\"obs.disabled\"\n >{{ 'selectByAttributes' | pluginTranslate: pluginId | async }}</button>\n </div>\n </div>\n\n <!-- Explicit variant selection (dropdown) -->\n <v-select\n *ngIf=\"variantSelectionMode === 'explicit'\"\n name=\"variantId\"\n [title]=\"'variantId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'variantIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.variantOptions\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variantsLoading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variantsLoading\"\n >\n </v-select>\n <div *ngIf=\"obs.variantsError\" class=\"loading-error\">{{ obs.variantsError }}</div>\n\n <!-- Attribute-based variant selection -->\n <div *ngIf=\"variantSelectionMode === 'attributes' && obs.selectedTemplateId\" class=\"variant-attributes-section\">\n <label class=\"variant-attributes-label\">{{ 'variantAttributes' | pluginTranslate: pluginId | async }}</label>\n <div class=\"variant-attributes-list\">\n <div *ngFor=\"let entry of variantAttributeEntries; let i = index\" class=\"variant-attribute-row\">\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeKey' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.key\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <input\n type=\"text\"\n class=\"variant-attribute-input\"\n [placeholder]=\"'attributeValue' | pluginTranslate: pluginId | async\"\n [(ngModel)]=\"entry.value\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <button\n type=\"button\"\n class=\"variant-attribute-remove-btn\"\n (click)=\"removeAttributeEntry(i)\"\n [disabled]=\"obs.disabled\"\n title=\"{{ 'removeAttribute' | pluginTranslate: pluginId | async }}\"\n >&times;</button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"variant-attribute-add-btn\"\n (click)=\"addAttributeEntry()\"\n [disabled]=\"obs.disabled\"\n >+ {{ 'addAttribute' | pluginTranslate: pluginId | async }}</button>\n </div>\n\n <v-select\n name=\"environmentId\"\n [title]=\"'environmentId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'environmentIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.environmentOptions\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environmentsLoading\"\n [required]=\"false\"\n [loading]=\"obs.environmentsLoading\"\n >\n </v-select>\n <div *ngIf=\"obs.environmentsError\" class=\"loading-error\">{{ obs.environmentsError }}</div>\n\n <v-select\n name=\"outputFormat\"\n [title]=\"'outputFormat' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'outputFormatTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"outputFormatOptions\"\n [defaultSelectionId]=\"obs.prefill?.outputFormat || 'PDF'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-select>\n\n <v-input\n name=\"filename\"\n [title]=\"'filename' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'filenameTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.filename\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"correlationId\"\n [title]=\"'correlationId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'correlationIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.correlationId\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"resultProcessVariable\"\n [title]=\"'resultProcessVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'resultProcessVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.resultProcessVariable\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n</v-form>\n\n<div *ngIf=\"templateFieldsError$ | async as templateFieldsError\" class=\"loading-error\">{{ templateFieldsError }}</div>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields$]=\"templateFields$\"\n [disabled$]=\"disabled$\"\n [prefillMapping$]=\"prefillDataMapping$\"\n [caseDefinitionKey]=\"caseDefinitionKey\"\n [processVariables]=\"processVariables\"\n (mappingChange)=\"onDataMappingChange($event)\"\n (requiredFieldsStatus)=\"onRequiredFieldsStatusChange($event)\"\n></epistola-data-mapping-tree>\n\n<div class=\"validation-summary\" *ngIf=\"(selectedTemplateId$ | async) && requiredFieldsStatus.total > 0\">\n <span *ngIf=\"requiredFieldsStatus.mapped === requiredFieldsStatus.total\" class=\"validation-complete\">\n {{ 'requiredFieldsComplete' | pluginTranslate: pluginId | async }}\n </span>\n <span *ngIf=\"requiredFieldsStatus.mapped < requiredFieldsStatus.total\" class=\"validation-incomplete\">\n {{ requiredFieldsStatus.mapped }} / {{ requiredFieldsStatus.total }}\n {{ 'validationSummary' | pluginTranslate: pluginId | async }}\n </span>\n</div>\n", styles: [".loading-error{padding:.25rem .75rem;font-size:.8125rem;color:#dc3545}.validation-summary{margin-top:.5rem;padding:.5rem .75rem;border-radius:4px;font-size:.875rem}.validation-summary .validation-complete{color:#198754}.validation-summary .validation-incomplete{color:#dc3545;font-weight:500}.variant-mode-toggle{margin-bottom:1rem;padding:0 .75rem}.variant-mode-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-mode-buttons{display:flex;gap:0;border:1px solid #d1d5db;border-radius:4px;overflow:hidden;width:fit-content}.variant-mode-btn{padding:.375rem .75rem;font-size:.8125rem;background:#fff;border:none;border-right:1px solid #d1d5db;cursor:pointer;color:#374151;transition:background-color .15s,color .15s}.variant-mode-btn:last-child{border-right:none}.variant-mode-btn:hover:not([disabled]){background:#f3f4f6}.variant-mode-btn.active{background:#2563eb;color:#fff}.variant-mode-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attributes-section{margin-bottom:1rem;padding:0 .75rem}.variant-attributes-label{display:block;font-size:.875rem;font-weight:500;margin-bottom:.375rem}.variant-attributes-list{display:flex;flex-direction:column;gap:.375rem}.variant-attribute-row{display:flex;gap:.375rem;align-items:center}.variant-attribute-input{flex:1;padding:.375rem .5rem;font-size:.8125rem;border:1px solid #d1d5db;border-radius:4px;outline:none}.variant-attribute-input:focus{border-color:#2563eb;box-shadow:0 0 0 1px #2563eb}.variant-attribute-input[disabled]{opacity:.5;background:#f9fafb}.variant-attribute-remove-btn{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-remove-btn:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.variant-attribute-remove-btn[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-add-btn{margin-top:.375rem;padding:.25rem .5rem;font-size:.8125rem;background:none;border:1px dashed #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.variant-attribute-add-btn:hover:not([disabled]){color:#2563eb;border-color:#2563eb}.variant-attribute-add-btn[disabled]{opacity:.5;cursor:not-allowed}\n"] }]
898
+ }], ctorParameters: () => [{ type: EpistolaPluginService }, { type: i2$2.ProcessLinkStateService }, { type: i0.ChangeDetectorRef }], propDecorators: { save$: [{
878
899
  type: Input
879
900
  }], disabled$: [{
880
901
  type: Input
@@ -932,10 +953,10 @@ class CheckJobStatusConfigurationComponent {
932
953
  });
933
954
  });
934
955
  }
935
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CheckJobStatusConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
936
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: CheckJobStatusConfigurationComponent, isStandalone: true, selector: "epistola-check-job-status-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"requestIdVariable\"\n [title]=\"'requestIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'requestIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.requestIdVariable || 'epistolaRequestId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"statusVariable\"\n [title]=\"'statusVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'statusVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.statusVariable || 'epistolaStatus'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"documentIdVariable\"\n [title]=\"'documentIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'documentIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.documentIdVariable || 'epistolaDocumentId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"errorMessageVariable\"\n [title]=\"'errorMessageVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'errorMessageVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.errorMessageVariable || 'epistolaErrorMessage'\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n</v-form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }] });
956
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CheckJobStatusConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
957
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: CheckJobStatusConfigurationComponent, isStandalone: true, selector: "epistola-check-job-status-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"requestIdVariable\"\n [title]=\"'requestIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'requestIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.requestIdVariable || 'epistolaRequestId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"statusVariable\"\n [title]=\"'statusVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'statusVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.statusVariable || 'epistolaStatus'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"documentIdVariable\"\n [title]=\"'documentIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'documentIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.documentIdVariable || 'epistolaDocumentId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"errorMessageVariable\"\n [title]=\"'errorMessageVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'errorMessageVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.errorMessageVariable || 'epistolaErrorMessage'\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n</v-form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }] });
937
958
  }
938
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CheckJobStatusConfigurationComponent, decorators: [{
959
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CheckJobStatusConfigurationComponent, decorators: [{
939
960
  type: Component,
940
961
  args: [{ selector: 'epistola-check-job-status-configuration', standalone: true, imports: [CommonModule, PluginTranslatePipeModule, FormModule, InputModule], template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"requestIdVariable\"\n [title]=\"'requestIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'requestIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.requestIdVariable || 'epistolaRequestId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"statusVariable\"\n [title]=\"'statusVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'statusVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.statusVariable || 'epistolaStatus'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"documentIdVariable\"\n [title]=\"'documentIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'documentIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.documentIdVariable || 'epistolaDocumentId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n\n <v-input\n name=\"errorMessageVariable\"\n [title]=\"'errorMessageVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'errorMessageVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.errorMessageVariable || 'epistolaErrorMessage'\"\n [disabled]=\"obs.disabled\"\n [required]=\"false\"\n >\n </v-input>\n</v-form>\n" }]
941
962
  }], propDecorators: { save$: [{
@@ -992,10 +1013,10 @@ class DownloadDocumentConfigurationComponent {
992
1013
  });
993
1014
  });
994
1015
  }
995
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DownloadDocumentConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
996
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: DownloadDocumentConfigurationComponent, isStandalone: true, selector: "epistola-download-document-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"documentIdVariable\"\n [title]=\"'documentIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'documentIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.documentIdVariable || 'epistolaDocumentId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"contentVariable\"\n [title]=\"'contentVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'contentVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.contentVariable || 'documentContent'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n</v-form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }] });
1016
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadDocumentConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1017
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: DownloadDocumentConfigurationComponent, isStandalone: true, selector: "epistola-download-document-configuration", inputs: { save$: "save$", disabled$: "disabled$", pluginId: "pluginId", prefillConfiguration$: "prefillConfiguration$" }, outputs: { valid: "valid", configuration: "configuration" }, ngImport: i0, template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"documentIdVariable\"\n [title]=\"'documentIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'documentIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.documentIdVariable || 'epistolaDocumentId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"contentVariable\"\n [title]=\"'contentVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'contentVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.contentVariable || 'documentContent'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n</v-form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: PluginTranslatePipeModule }, { kind: "pipe", type: i2$1.PluginTranslatePipe, name: "pluginTranslate" }, { kind: "ngmodule", type: FormModule }, { kind: "component", type: i3.FormComponent, selector: "v-form", inputs: ["className"], outputs: ["valueChange"] }, { kind: "ngmodule", type: InputModule }, { kind: "component", type: i3.InputComponent, selector: "v-input", inputs: ["name", "type", "title", "titleTranslationKey", "defaultValue", "widthPx", "fullWidth", "margin", "smallMargin", "disabled", "step", "min", "maxLength", "tooltip", "required", "hideNumberSpinBox", "smallLabel", "rows", "clear$", "carbonTheme", "placeholder", "dataTestId", "trim", "presetsTitle", "presetOptions"], outputs: ["valueChange"] }] });
997
1018
  }
998
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DownloadDocumentConfigurationComponent, decorators: [{
1019
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadDocumentConfigurationComponent, decorators: [{
999
1020
  type: Component,
1000
1021
  args: [{ selector: 'epistola-download-document-configuration', standalone: true, imports: [CommonModule, PluginTranslatePipeModule, FormModule, InputModule], template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: safeDisabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null\n } as obs\"\n>\n <v-input\n name=\"documentIdVariable\"\n [title]=\"'documentIdVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'documentIdVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.documentIdVariable || 'epistolaDocumentId'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n\n <v-input\n name=\"contentVariable\"\n [title]=\"'contentVariable' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'contentVariableTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [defaultValue]=\"obs.prefill?.contentVariable || 'documentContent'\"\n [disabled]=\"obs.disabled\"\n [required]=\"true\"\n >\n </v-input>\n</v-form>\n" }]
1001
1022
  }], propDecorators: { save$: [{
@@ -1057,8 +1078,8 @@ class EpistolaDownloadComponent {
1057
1078
  },
1058
1079
  });
1059
1080
  }
1060
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaDownloadComponent, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
1061
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: EpistolaDownloadComponent, isStandalone: true, selector: "epistola-download-component", inputs: { value: "value", disabled: "disabled", filename: "filename", label: "label" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
1081
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaDownloadComponent, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
1082
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: EpistolaDownloadComponent, isStandalone: true, selector: "epistola-download-component", inputs: { value: "value", disabled: "disabled", filename: "filename", label: "label" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
1062
1083
  <button
1063
1084
  type="button"
1064
1085
  class="btn btn-outline-primary"
@@ -1071,7 +1092,7 @@ class EpistolaDownloadComponent {
1071
1092
  <span *ngIf="error" class="text-danger ml-2">{{ error }}</span>
1072
1093
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1073
1094
  }
1074
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaDownloadComponent, decorators: [{
1095
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaDownloadComponent, decorators: [{
1075
1096
  type: Component,
1076
1097
  args: [{
1077
1098
  standalone: true,
@@ -1102,9 +1123,380 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
1102
1123
  type: Input
1103
1124
  }] } });
1104
1125
 
1126
+ class EpistolaRetryFormComponent {
1127
+ epistolaPluginService;
1128
+ formIoStateService;
1129
+ cdr;
1130
+ http;
1131
+ sanitizer;
1132
+ configService;
1133
+ value;
1134
+ valueChange = new EventEmitter();
1135
+ disabled = false;
1136
+ label = 'Document Data';
1137
+ sourceActivityId;
1138
+ formDefinition;
1139
+ submission;
1140
+ loading = true;
1141
+ error = null;
1142
+ previewUrl = null;
1143
+ previewLoading = false;
1144
+ previewError = null;
1145
+ previewExpanded = false;
1146
+ loaded = false;
1147
+ loadSubscription;
1148
+ previewSubscription;
1149
+ previewSubject = new Subject();
1150
+ currentBlobUrl = null;
1151
+ resolvedSourceActivityId;
1152
+ processDefinitionKey;
1153
+ apiEndpoint;
1154
+ formOptions = {
1155
+ noAlerts: true,
1156
+ buttonSettings: { showCancel: false, showSubmit: false, showPrevious: false, showNext: false }
1157
+ };
1158
+ constructor(epistolaPluginService, formIoStateService, cdr, http, sanitizer, configService) {
1159
+ this.epistolaPluginService = epistolaPluginService;
1160
+ this.formIoStateService = formIoStateService;
1161
+ this.cdr = cdr;
1162
+ this.http = http;
1163
+ this.sanitizer = sanitizer;
1164
+ this.configService = configService;
1165
+ this.apiEndpoint = `${this.configService.config.valtimoApi.endpointUri}v1/plugin/epistola`;
1166
+ // Debounce preview calls
1167
+ this.previewSubscription = this.previewSubject.pipe(debounceTime(1500)).subscribe(data => {
1168
+ this.loadPreview(data);
1169
+ });
1170
+ }
1171
+ ngOnChanges(changes) {
1172
+ if (!this.loaded) {
1173
+ this.loaded = true;
1174
+ this.loadForm();
1175
+ }
1176
+ }
1177
+ ngOnDestroy() {
1178
+ this.loadSubscription?.unsubscribe();
1179
+ this.previewSubscription?.unsubscribe();
1180
+ if (this.currentBlobUrl) {
1181
+ URL.revokeObjectURL(this.currentBlobUrl);
1182
+ }
1183
+ }
1184
+ togglePreview() {
1185
+ this.previewExpanded = !this.previewExpanded;
1186
+ this.cdr.markForCheck();
1187
+ }
1188
+ onFormChange(event) {
1189
+ if (event?.data) {
1190
+ const json = JSON.stringify(event.data);
1191
+ this.value = json; // Formio reads element.value on change event
1192
+ this.valueChange.emit(json);
1193
+ // Trigger debounced preview
1194
+ this.previewSubject.next(event.data);
1195
+ }
1196
+ }
1197
+ loadPreview(formData) {
1198
+ const documentId = this.formIoStateService.documentId;
1199
+ const processInstanceId = this.formIoStateService.processInstanceId;
1200
+ if (!documentId || !processInstanceId)
1201
+ return;
1202
+ this.previewLoading = true;
1203
+ this.previewError = null;
1204
+ this.cdr.markForCheck();
1205
+ // Revoke previous blob URL to prevent memory leaks
1206
+ if (this.currentBlobUrl) {
1207
+ URL.revokeObjectURL(this.currentBlobUrl);
1208
+ this.currentBlobUrl = null;
1209
+ }
1210
+ this.http.post(`${this.apiEndpoint}/preview`, {
1211
+ documentId,
1212
+ processInstanceId,
1213
+ sourceActivityId: this.sourceActivityId || null,
1214
+ overrides: formData
1215
+ }, { responseType: 'blob' }).subscribe({
1216
+ next: (blob) => {
1217
+ this.currentBlobUrl = URL.createObjectURL(blob);
1218
+ this.previewUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.currentBlobUrl);
1219
+ this.previewError = null;
1220
+ this.previewLoading = false;
1221
+ this.cdr.markForCheck();
1222
+ },
1223
+ error: (err) => {
1224
+ this.previewUrl = null;
1225
+ // Try to extract error message from JSON response body
1226
+ if (err.error instanceof Blob) {
1227
+ err.error.text().then((text) => {
1228
+ try {
1229
+ const body = JSON.parse(text);
1230
+ this.previewError = body.details || body.error || 'Preview could not be generated';
1231
+ }
1232
+ catch {
1233
+ this.previewError = 'Preview could not be generated';
1234
+ }
1235
+ this.previewLoading = false;
1236
+ this.cdr.markForCheck();
1237
+ });
1238
+ }
1239
+ else {
1240
+ this.previewError = err.error?.error || 'Preview could not be generated';
1241
+ this.previewLoading = false;
1242
+ this.cdr.markForCheck();
1243
+ }
1244
+ }
1245
+ });
1246
+ }
1247
+ loadForm() {
1248
+ const processInstanceId = this.formIoStateService.processInstanceId;
1249
+ const documentId = this.formIoStateService.documentId;
1250
+ if (!processInstanceId) {
1251
+ this.error = 'Could not determine process instance ID.';
1252
+ this.loading = false;
1253
+ this.cdr.markForCheck();
1254
+ return;
1255
+ }
1256
+ this.loadSubscription = this.epistolaPluginService.getRetryForm(processInstanceId, documentId ?? undefined, this.sourceActivityId).subscribe({
1257
+ next: (form) => {
1258
+ this.formDefinition = form;
1259
+ if (this.value) {
1260
+ try {
1261
+ this.submission = { data: JSON.parse(this.value) };
1262
+ }
1263
+ catch {
1264
+ // value is not valid JSON, start fresh
1265
+ }
1266
+ }
1267
+ this.loading = false;
1268
+ this.cdr.markForCheck();
1269
+ },
1270
+ error: (err) => {
1271
+ console.error('Failed to load retry form', err);
1272
+ this.error = 'Failed to load the retry form. Please try again.';
1273
+ this.loading = false;
1274
+ this.cdr.markForCheck();
1275
+ }
1276
+ });
1277
+ }
1278
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaRetryFormComponent, deps: [{ token: EpistolaPluginService }, { token: i3.FormIoStateService }, { token: i0.ChangeDetectorRef }, { token: i1.HttpClient }, { token: i4$1.DomSanitizer }, { token: i2.ConfigService }], target: i0.ɵɵFactoryTarget.Component });
1279
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: EpistolaRetryFormComponent, isStandalone: true, selector: "epistola-retry-form-component", inputs: { value: "value", disabled: "disabled", label: "label", sourceActivityId: "sourceActivityId" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: `
1280
+ <div *ngIf="loading" class="epistola-retry-loading">Loading form...</div>
1281
+ <div *ngIf="error" class="epistola-retry-error">{{ error }}</div>
1282
+ <div *ngIf="formDefinition && !loading" class="epistola-retry-container" [class.preview-expanded]="previewExpanded">
1283
+ <div class="epistola-retry-form" [hidden]="previewExpanded">
1284
+ <formio
1285
+ [form]="formDefinition"
1286
+ [submission]="submission"
1287
+ (change)="onFormChange($event)"
1288
+ [options]="formOptions"
1289
+ ></formio>
1290
+ </div>
1291
+ <div class="epistola-retry-preview">
1292
+ <div class="preview-header">
1293
+ <span>Preview</span>
1294
+ <button type="button" class="preview-toggle" (click)="togglePreview()">
1295
+ {{ previewExpanded ? 'Show form' : 'Expand' }}
1296
+ </button>
1297
+ </div>
1298
+ <div *ngIf="previewLoading" class="preview-loading">Generating preview...</div>
1299
+ <object *ngIf="previewUrl && !previewLoading" [data]="previewUrl" type="application/pdf" class="preview-pdf">
1300
+ PDF preview not supported in this browser.
1301
+ </object>
1302
+ <div *ngIf="previewError" class="preview-error">{{ previewError }}</div>
1303
+ <div *ngIf="!previewUrl && !previewLoading && !previewError" class="preview-empty">
1304
+ Edit fields to see a preview
1305
+ </div>
1306
+ </div>
1307
+ </div>
1308
+ `, isInline: true, styles: [".epistola-retry-loading{padding:1rem;color:#6c757d}.epistola-retry-error{padding:.5rem;color:#dc3545}.epistola-retry-container{display:flex;gap:1rem}.epistola-retry-form{flex:2;min-width:0}.epistola-retry-preview{flex:1;min-width:0;border:1px solid #dee2e6;border-radius:4px;padding:1rem;background:#f8f9fa;display:flex;flex-direction:column}.preview-expanded .epistola-retry-preview{flex:1}.preview-header{display:flex;justify-content:space-between;align-items:center;font-weight:700;margin-bottom:.5rem;color:#495057}.preview-toggle{background:none;border:1px solid #6c757d;border-radius:4px;color:#6c757d;padding:.2rem .5rem;font-size:.75rem;cursor:pointer}.preview-toggle:hover{background:#e9ecef}.preview-loading{color:#6c757d;font-style:italic}.preview-pdf{width:100%;flex:1;min-height:500px}.preview-expanded .preview-pdf{min-height:80vh}.preview-error{color:#dc3545}.preview-empty{color:#6c757d;font-style:italic}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormioModule }, { kind: "component", type: i7.FormioComponent, selector: "formio" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1309
+ }
1310
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaRetryFormComponent, decorators: [{
1311
+ type: Component,
1312
+ args: [{ standalone: true, imports: [CommonModule, FormioModule], selector: 'epistola-retry-form-component', changeDetection: ChangeDetectionStrategy.OnPush, template: `
1313
+ <div *ngIf="loading" class="epistola-retry-loading">Loading form...</div>
1314
+ <div *ngIf="error" class="epistola-retry-error">{{ error }}</div>
1315
+ <div *ngIf="formDefinition && !loading" class="epistola-retry-container" [class.preview-expanded]="previewExpanded">
1316
+ <div class="epistola-retry-form" [hidden]="previewExpanded">
1317
+ <formio
1318
+ [form]="formDefinition"
1319
+ [submission]="submission"
1320
+ (change)="onFormChange($event)"
1321
+ [options]="formOptions"
1322
+ ></formio>
1323
+ </div>
1324
+ <div class="epistola-retry-preview">
1325
+ <div class="preview-header">
1326
+ <span>Preview</span>
1327
+ <button type="button" class="preview-toggle" (click)="togglePreview()">
1328
+ {{ previewExpanded ? 'Show form' : 'Expand' }}
1329
+ </button>
1330
+ </div>
1331
+ <div *ngIf="previewLoading" class="preview-loading">Generating preview...</div>
1332
+ <object *ngIf="previewUrl && !previewLoading" [data]="previewUrl" type="application/pdf" class="preview-pdf">
1333
+ PDF preview not supported in this browser.
1334
+ </object>
1335
+ <div *ngIf="previewError" class="preview-error">{{ previewError }}</div>
1336
+ <div *ngIf="!previewUrl && !previewLoading && !previewError" class="preview-empty">
1337
+ Edit fields to see a preview
1338
+ </div>
1339
+ </div>
1340
+ </div>
1341
+ `, styles: [".epistola-retry-loading{padding:1rem;color:#6c757d}.epistola-retry-error{padding:.5rem;color:#dc3545}.epistola-retry-container{display:flex;gap:1rem}.epistola-retry-form{flex:2;min-width:0}.epistola-retry-preview{flex:1;min-width:0;border:1px solid #dee2e6;border-radius:4px;padding:1rem;background:#f8f9fa;display:flex;flex-direction:column}.preview-expanded .epistola-retry-preview{flex:1}.preview-header{display:flex;justify-content:space-between;align-items:center;font-weight:700;margin-bottom:.5rem;color:#495057}.preview-toggle{background:none;border:1px solid #6c757d;border-radius:4px;color:#6c757d;padding:.2rem .5rem;font-size:.75rem;cursor:pointer}.preview-toggle:hover{background:#e9ecef}.preview-loading{color:#6c757d;font-style:italic}.preview-pdf{width:100%;flex:1;min-height:500px}.preview-expanded .preview-pdf{min-height:80vh}.preview-error{color:#dc3545}.preview-empty{color:#6c757d;font-style:italic}\n"] }]
1342
+ }], ctorParameters: () => [{ type: EpistolaPluginService }, { type: i3.FormIoStateService }, { type: i0.ChangeDetectorRef }, { type: i1.HttpClient }, { type: i4$1.DomSanitizer }, { type: i2.ConfigService }], propDecorators: { value: [{
1343
+ type: Input
1344
+ }], valueChange: [{
1345
+ type: Output
1346
+ }], disabled: [{
1347
+ type: Input
1348
+ }], label: [{
1349
+ type: Input
1350
+ }], sourceActivityId: [{
1351
+ type: Input
1352
+ }] } });
1353
+
1354
+ class EpistolaPreviewButtonComponent {
1355
+ http;
1356
+ sanitizer;
1357
+ configService;
1358
+ value;
1359
+ valueChange = new EventEmitter();
1360
+ disabled = false;
1361
+ label = 'Preview PDF';
1362
+ modalOpen = false;
1363
+ loading = false;
1364
+ previewLoading = false;
1365
+ previewError = null;
1366
+ previewUrl = null;
1367
+ currentBlobUrl = null;
1368
+ apiEndpoint;
1369
+ get buttonLabel() {
1370
+ return this.label || 'Preview PDF';
1371
+ }
1372
+ constructor(http, sanitizer, configService) {
1373
+ this.http = http;
1374
+ this.sanitizer = sanitizer;
1375
+ this.configService = configService;
1376
+ this.apiEndpoint = `${this.configService.config.valtimoApi.endpointUri}v1/plugin/epistola`;
1377
+ }
1378
+ ngOnDestroy() {
1379
+ this.revokeBlobUrl();
1380
+ }
1381
+ hasRequiredData() {
1382
+ return !!(this.value?.documentId && this.value?.tenantId);
1383
+ }
1384
+ openPreview() {
1385
+ if (!this.hasRequiredData() || this.loading)
1386
+ return;
1387
+ this.modalOpen = true;
1388
+ this.previewLoading = true;
1389
+ this.previewError = null;
1390
+ this.revokeBlobUrl();
1391
+ const { documentId, tenantId } = this.value;
1392
+ const url = `${this.apiEndpoint}/documents/${encodeURIComponent(documentId)}/download`
1393
+ + `?tenantId=${encodeURIComponent(tenantId)}`
1394
+ + `&filename=preview.pdf`;
1395
+ this.http.get(url, { responseType: 'blob' }).subscribe({
1396
+ next: (blob) => {
1397
+ this.currentBlobUrl = URL.createObjectURL(blob);
1398
+ this.previewUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.currentBlobUrl);
1399
+ this.previewLoading = false;
1400
+ },
1401
+ error: () => {
1402
+ this.previewError = 'Could not load the document.';
1403
+ this.previewLoading = false;
1404
+ }
1405
+ });
1406
+ }
1407
+ closePreview() {
1408
+ this.modalOpen = false;
1409
+ this.revokeBlobUrl();
1410
+ this.previewUrl = null;
1411
+ this.previewError = null;
1412
+ }
1413
+ revokeBlobUrl() {
1414
+ if (this.currentBlobUrl) {
1415
+ URL.revokeObjectURL(this.currentBlobUrl);
1416
+ this.currentBlobUrl = null;
1417
+ }
1418
+ }
1419
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPreviewButtonComponent, deps: [{ token: i1.HttpClient }, { token: i4$1.DomSanitizer }, { token: i2.ConfigService }], target: i0.ɵɵFactoryTarget.Component });
1420
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: EpistolaPreviewButtonComponent, isStandalone: true, selector: "epistola-preview-button-component", inputs: { value: "value", disabled: "disabled", label: "label" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
1421
+ <button
1422
+ type="button"
1423
+ class="btn btn-outline-secondary"
1424
+ [disabled]="disabled || loading || !hasRequiredData()"
1425
+ (click)="openPreview()"
1426
+ >
1427
+ <i class="mdi mdi-eye mr-1"></i>
1428
+ {{ loading ? 'Loading...' : buttonLabel }}
1429
+ </button>
1430
+
1431
+ <div *ngIf="modalOpen" class="preview-modal-overlay" (click)="closePreview()">
1432
+ <div class="preview-modal-content" (click)="$event.stopPropagation()">
1433
+ <div class="preview-modal-header">
1434
+ <span>Document Preview</span>
1435
+ <button type="button" class="preview-modal-close" (click)="closePreview()">&times;</button>
1436
+ </div>
1437
+ <div class="preview-modal-body">
1438
+ <div *ngIf="previewLoading" class="preview-loading">Generating preview...</div>
1439
+ <div *ngIf="previewError" class="preview-error">{{ previewError }}</div>
1440
+ <object
1441
+ *ngIf="previewUrl && !previewLoading"
1442
+ [data]="previewUrl"
1443
+ type="application/pdf"
1444
+ class="preview-pdf"
1445
+ >
1446
+ PDF preview is not supported in this browser.
1447
+ </object>
1448
+ </div>
1449
+ </div>
1450
+ </div>
1451
+ `, isInline: true, styles: [".preview-modal-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:10000}.preview-modal-content{background:#fff;border-radius:8px;width:90vw;height:90vh;max-width:1200px;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 8px 32px #0000004d}.preview-modal-header{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;border-bottom:1px solid #dee2e6;font-weight:700;font-size:1rem}.preview-modal-close{background:none;border:none;font-size:1.5rem;cursor:pointer;color:#6c757d;line-height:1;padding:0 .25rem}.preview-modal-close:hover{color:#333}.preview-modal-body{flex:1;overflow:hidden;display:flex;flex-direction:column}.preview-loading,.preview-error{padding:2rem;text-align:center}.preview-error{color:#dc3545}.preview-pdf{width:100%;flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1452
+ }
1453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPreviewButtonComponent, decorators: [{
1454
+ type: Component,
1455
+ args: [{ standalone: true, imports: [CommonModule], selector: 'epistola-preview-button-component', template: `
1456
+ <button
1457
+ type="button"
1458
+ class="btn btn-outline-secondary"
1459
+ [disabled]="disabled || loading || !hasRequiredData()"
1460
+ (click)="openPreview()"
1461
+ >
1462
+ <i class="mdi mdi-eye mr-1"></i>
1463
+ {{ loading ? 'Loading...' : buttonLabel }}
1464
+ </button>
1465
+
1466
+ <div *ngIf="modalOpen" class="preview-modal-overlay" (click)="closePreview()">
1467
+ <div class="preview-modal-content" (click)="$event.stopPropagation()">
1468
+ <div class="preview-modal-header">
1469
+ <span>Document Preview</span>
1470
+ <button type="button" class="preview-modal-close" (click)="closePreview()">&times;</button>
1471
+ </div>
1472
+ <div class="preview-modal-body">
1473
+ <div *ngIf="previewLoading" class="preview-loading">Generating preview...</div>
1474
+ <div *ngIf="previewError" class="preview-error">{{ previewError }}</div>
1475
+ <object
1476
+ *ngIf="previewUrl && !previewLoading"
1477
+ [data]="previewUrl"
1478
+ type="application/pdf"
1479
+ class="preview-pdf"
1480
+ >
1481
+ PDF preview is not supported in this browser.
1482
+ </object>
1483
+ </div>
1484
+ </div>
1485
+ </div>
1486
+ `, styles: [".preview-modal-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:10000}.preview-modal-content{background:#fff;border-radius:8px;width:90vw;height:90vh;max-width:1200px;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 8px 32px #0000004d}.preview-modal-header{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;border-bottom:1px solid #dee2e6;font-weight:700;font-size:1rem}.preview-modal-close{background:none;border:none;font-size:1.5rem;cursor:pointer;color:#6c757d;line-height:1;padding:0 .25rem}.preview-modal-close:hover{color:#333}.preview-modal-body{flex:1;overflow:hidden;display:flex;flex-direction:column}.preview-loading,.preview-error{padding:2rem;text-align:center}.preview-error{color:#dc3545}.preview-pdf{width:100%;flex:1}\n"] }]
1487
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i4$1.DomSanitizer }, { type: i2.ConfigService }], propDecorators: { value: [{
1488
+ type: Input
1489
+ }], valueChange: [{
1490
+ type: Output
1491
+ }], disabled: [{
1492
+ type: Input
1493
+ }], label: [{
1494
+ type: Input
1495
+ }] } });
1496
+
1105
1497
  class EpistolaPluginModule {
1106
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1107
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.17", ngImport: i0, type: EpistolaPluginModule, imports: [CommonModule,
1498
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1499
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, imports: [CommonModule,
1108
1500
  HttpClientModule,
1109
1501
  PluginTranslatePipeModule,
1110
1502
  FormModule,
@@ -1116,14 +1508,18 @@ class EpistolaPluginModule {
1116
1508
  DownloadDocumentConfigurationComponent,
1117
1509
  DataMappingTreeComponent,
1118
1510
  FieldTreeComponent,
1119
- EpistolaDownloadComponent], exports: [EpistolaConfigurationComponent,
1511
+ EpistolaDownloadComponent,
1512
+ EpistolaRetryFormComponent,
1513
+ EpistolaPreviewButtonComponent], exports: [EpistolaConfigurationComponent,
1120
1514
  GenerateDocumentConfigurationComponent,
1121
1515
  CheckJobStatusConfigurationComponent,
1122
1516
  DownloadDocumentConfigurationComponent,
1123
1517
  DataMappingTreeComponent,
1124
1518
  FieldTreeComponent,
1125
- EpistolaDownloadComponent] });
1126
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaPluginModule, providers: [
1519
+ EpistolaDownloadComponent,
1520
+ EpistolaRetryFormComponent,
1521
+ EpistolaPreviewButtonComponent] });
1522
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, providers: [
1127
1523
  EpistolaPluginService
1128
1524
  ], imports: [CommonModule,
1129
1525
  HttpClientModule,
@@ -1137,9 +1533,11 @@ class EpistolaPluginModule {
1137
1533
  DownloadDocumentConfigurationComponent,
1138
1534
  DataMappingTreeComponent,
1139
1535
  FieldTreeComponent,
1140
- EpistolaDownloadComponent] });
1536
+ EpistolaDownloadComponent,
1537
+ EpistolaRetryFormComponent,
1538
+ EpistolaPreviewButtonComponent] });
1141
1539
  }
1142
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpistolaPluginModule, decorators: [{
1540
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, decorators: [{
1143
1541
  type: NgModule,
1144
1542
  args: [{
1145
1543
  imports: [
@@ -1155,7 +1553,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
1155
1553
  DownloadDocumentConfigurationComponent,
1156
1554
  DataMappingTreeComponent,
1157
1555
  FieldTreeComponent,
1158
- EpistolaDownloadComponent
1556
+ EpistolaDownloadComponent,
1557
+ EpistolaRetryFormComponent,
1558
+ EpistolaPreviewButtonComponent
1159
1559
  ],
1160
1560
  exports: [
1161
1561
  EpistolaConfigurationComponent,
@@ -1164,7 +1564,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
1164
1564
  DownloadDocumentConfigurationComponent,
1165
1565
  DataMappingTreeComponent,
1166
1566
  FieldTreeComponent,
1167
- EpistolaDownloadComponent
1567
+ EpistolaDownloadComponent,
1568
+ EpistolaRetryFormComponent,
1569
+ EpistolaPreviewButtonComponent
1168
1570
  ],
1169
1571
  providers: [
1170
1572
  EpistolaPluginService
@@ -1381,6 +1783,36 @@ function registerEpistolaDownloadComponent(injector) {
1381
1783
  }
1382
1784
  }
1383
1785
 
1786
+ const EPISTOLA_RETRY_FORM_OPTIONS = {
1787
+ type: 'epistola-retry-form',
1788
+ selector: 'epistola-retry-form-element',
1789
+ title: 'Epistola Retry Form',
1790
+ group: 'basic',
1791
+ icon: 'refresh',
1792
+ emptyValue: null,
1793
+ fieldOptions: ['sourceActivityId', 'label'], // sourceActivityId is optional (set via BPMN input parameter)
1794
+ };
1795
+ function registerEpistolaRetryFormComponent(injector) {
1796
+ if (!customElements.get(EPISTOLA_RETRY_FORM_OPTIONS.selector)) {
1797
+ registerCustomFormioComponent(EPISTOLA_RETRY_FORM_OPTIONS, EpistolaRetryFormComponent, injector);
1798
+ }
1799
+ }
1800
+
1801
+ const EPISTOLA_PREVIEW_BUTTON_OPTIONS = {
1802
+ type: 'epistola-preview-button',
1803
+ selector: 'epistola-preview-button-element',
1804
+ title: 'Epistola Preview',
1805
+ group: 'basic',
1806
+ icon: 'eye',
1807
+ emptyValue: null,
1808
+ fieldOptions: ['label'],
1809
+ };
1810
+ function registerEpistolaPreviewButtonComponent(injector) {
1811
+ if (!customElements.get(EPISTOLA_PREVIEW_BUTTON_OPTIONS.selector)) {
1812
+ registerCustomFormioComponent(EPISTOLA_PREVIEW_BUTTON_OPTIONS, EpistolaPreviewButtonComponent, injector);
1813
+ }
1814
+ }
1815
+
1384
1816
  /*
1385
1817
  * Public API Surface of epistola plugin
1386
1818
  */
@@ -1389,5 +1821,5 @@ function registerEpistolaDownloadComponent(injector) {
1389
1821
  * Generated bundle index. Do not edit.
1390
1822
  */
1391
1823
 
1392
- export { CheckJobStatusConfigurationComponent, DataMappingTreeComponent, DownloadDocumentConfigurationComponent, EPISTOLA_DOWNLOAD_OPTIONS, EpistolaConfigurationComponent, EpistolaDownloadComponent, EpistolaPluginModule, EpistolaPluginService, FieldTreeComponent, GenerateDocumentConfigurationComponent, epistolaPluginSpecification, registerEpistolaDownloadComponent };
1824
+ export { CheckJobStatusConfigurationComponent, DataMappingTreeComponent, DownloadDocumentConfigurationComponent, EPISTOLA_DOWNLOAD_OPTIONS, EPISTOLA_PREVIEW_BUTTON_OPTIONS, EPISTOLA_RETRY_FORM_OPTIONS, EpistolaConfigurationComponent, EpistolaDownloadComponent, EpistolaPluginModule, EpistolaPluginService, EpistolaPreviewButtonComponent, EpistolaRetryFormComponent, FieldTreeComponent, GenerateDocumentConfigurationComponent, epistolaPluginSpecification, registerEpistolaDownloadComponent, registerEpistolaPreviewButtonComponent, registerEpistolaRetryFormComponent };
1393
1825
  //# sourceMappingURL=epistola.app-valtimo-plugin.mjs.map