@epistola.app/valtimo-plugin 0.4.5 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/epistola.app-valtimo-plugin.mjs +138 -88
- package/fesm2022/epistola.app-valtimo-plugin.mjs.map +1 -1
- package/lib/components/generate-document-configuration/generate-document-configuration.component.d.ts +22 -6
- package/lib/models/config.d.ts +1 -0
- package/lib/models/template.d.ts +10 -0
- package/lib/services/epistola-plugin.service.d.ts +11 -7
- package/package.json +1 -1
|
@@ -9,8 +9,8 @@ import * as i2$1 from '@valtimo/plugin';
|
|
|
9
9
|
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
|
-
import { BehaviorSubject, combineLatest, take, Subject,
|
|
13
|
-
import { startWith, delay, takeUntil, filter, map, tap, switchMap, catchError,
|
|
12
|
+
import { BehaviorSubject, combineLatest, take, Subject, of, merge } from 'rxjs';
|
|
13
|
+
import { startWith, delay, shareReplay, take as take$1, takeUntil, filter, map, distinctUntilChanged, tap, switchMap, catchError, 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';
|
|
@@ -46,22 +46,34 @@ class EpistolaPluginService {
|
|
|
46
46
|
this.apiEndpoint = `${this.configService.config.valtimoApi.endpointUri}v1/plugin/epistola`;
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
* Get all available
|
|
49
|
+
* Get all available catalogs for a plugin configuration.
|
|
50
50
|
*/
|
|
51
|
-
|
|
52
|
-
return this.http.get(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/
|
|
51
|
+
getCatalogs(pluginConfigurationId) {
|
|
52
|
+
return this.http.get(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/catalogs`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get all available templates for a plugin configuration and catalog.
|
|
56
|
+
*/
|
|
57
|
+
getTemplates(pluginConfigurationId, catalogId) {
|
|
58
|
+
const params = {};
|
|
59
|
+
if (catalogId)
|
|
60
|
+
params['catalogId'] = catalogId;
|
|
61
|
+
return this.http.get(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/templates`, { params });
|
|
53
62
|
}
|
|
54
63
|
/**
|
|
55
64
|
* Get template details including its fields.
|
|
56
65
|
*/
|
|
57
|
-
getTemplateDetails(pluginConfigurationId, templateId) {
|
|
58
|
-
return this.http.get(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/templates/${templateId}
|
|
66
|
+
getTemplateDetails(pluginConfigurationId, templateId, catalogId) {
|
|
67
|
+
return this.http.get(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/templates/${templateId}`, { params: { catalogId } });
|
|
59
68
|
}
|
|
60
69
|
/**
|
|
61
|
-
* Get all attribute definitions for a plugin configuration's tenant.
|
|
70
|
+
* Get all attribute definitions for a plugin configuration's tenant and catalog.
|
|
62
71
|
*/
|
|
63
|
-
getAttributes(pluginConfigurationId) {
|
|
64
|
-
|
|
72
|
+
getAttributes(pluginConfigurationId, catalogId) {
|
|
73
|
+
const params = {};
|
|
74
|
+
if (catalogId)
|
|
75
|
+
params['catalogId'] = catalogId;
|
|
76
|
+
return this.http.get(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/attributes`, { params });
|
|
65
77
|
}
|
|
66
78
|
/**
|
|
67
79
|
* Get all available environments for a plugin configuration.
|
|
@@ -72,8 +84,11 @@ class EpistolaPluginService {
|
|
|
72
84
|
/**
|
|
73
85
|
* Get all variants for a specific template.
|
|
74
86
|
*/
|
|
75
|
-
getVariants(pluginConfigurationId, templateId) {
|
|
76
|
-
|
|
87
|
+
getVariants(pluginConfigurationId, templateId, catalogId) {
|
|
88
|
+
const params = {};
|
|
89
|
+
if (catalogId)
|
|
90
|
+
params['catalogId'] = catalogId;
|
|
91
|
+
return this.http.get(`${this.apiEndpoint}/configurations/${pluginConfigurationId}/templates/${templateId}/variants`, { params });
|
|
77
92
|
}
|
|
78
93
|
/**
|
|
79
94
|
* Discover process variable names for a given process definition.
|
|
@@ -666,6 +681,7 @@ class GenerateDocumentConfigurationComponent {
|
|
|
666
681
|
context$;
|
|
667
682
|
valid = new EventEmitter();
|
|
668
683
|
configuration = new EventEmitter();
|
|
684
|
+
catalogs$ = new BehaviorSubject(initialResource([]));
|
|
669
685
|
templates$ = new BehaviorSubject(initialResource([]));
|
|
670
686
|
variants$ = new BehaviorSubject(initialResource([]));
|
|
671
687
|
environments$ = new BehaviorSubject(initialResource([]));
|
|
@@ -675,6 +691,8 @@ class GenerateDocumentConfigurationComponent {
|
|
|
675
691
|
{ id: 'PDF', text: 'PDF' },
|
|
676
692
|
{ id: 'HTML', text: 'HTML' }
|
|
677
693
|
];
|
|
694
|
+
selectedCatalogId$ = new BehaviorSubject('');
|
|
695
|
+
/** Composite ID: "catalogId/templateId" */
|
|
678
696
|
selectedTemplateId$ = new BehaviorSubject('');
|
|
679
697
|
selectedVariantId$ = new BehaviorSubject('');
|
|
680
698
|
variantSelectionMode = 'explicit';
|
|
@@ -689,20 +707,18 @@ class GenerateDocumentConfigurationComponent {
|
|
|
689
707
|
formValue$ = new BehaviorSubject(null);
|
|
690
708
|
valid$ = new BehaviorSubject(false);
|
|
691
709
|
pluginConfigurationId$ = new BehaviorSubject('');
|
|
710
|
+
/** Resolves once with the prefill config (or empty config if none). */
|
|
711
|
+
prefill$;
|
|
692
712
|
constructor(epistolaPluginService, processLinkStateService, cdr) {
|
|
693
713
|
this.epistolaPluginService = epistolaPluginService;
|
|
694
714
|
this.processLinkStateService = processLinkStateService;
|
|
695
715
|
this.cdr = cdr;
|
|
696
716
|
}
|
|
697
717
|
ngOnInit() {
|
|
718
|
+
this.prefill$ = this.resolvePrefill$();
|
|
698
719
|
this.initContext();
|
|
699
|
-
this.initPrefill();
|
|
700
720
|
this.initPluginConfiguration();
|
|
701
|
-
this.
|
|
702
|
-
this.initEnvironmentsLoading();
|
|
703
|
-
this.initAttributesLoading();
|
|
704
|
-
this.initVariantsLoading();
|
|
705
|
-
this.initTemplateFieldsLoading();
|
|
721
|
+
this.initCascade();
|
|
706
722
|
this.openSaveSubscription();
|
|
707
723
|
}
|
|
708
724
|
ngOnDestroy() {
|
|
@@ -713,6 +729,13 @@ class GenerateDocumentConfigurationComponent {
|
|
|
713
729
|
formValueChange(formOutput) {
|
|
714
730
|
const formValue = formOutput;
|
|
715
731
|
this.formValue$.next(formValue);
|
|
732
|
+
// When catalog changes, reset template and variant selection
|
|
733
|
+
if (formValue.catalogId && formValue.catalogId !== this.selectedCatalogId$.getValue()) {
|
|
734
|
+
this.selectedCatalogId$.next(formValue.catalogId);
|
|
735
|
+
this.selectedTemplateId$.next('');
|
|
736
|
+
this.selectedVariantId$.next('');
|
|
737
|
+
}
|
|
738
|
+
// templateId from v-select is the template ID within the selected catalog
|
|
716
739
|
if (formValue.templateId && formValue.templateId !== this.selectedTemplateId$.getValue()) {
|
|
717
740
|
this.selectedTemplateId$.next(formValue.templateId);
|
|
718
741
|
this.selectedVariantId$.next('');
|
|
@@ -781,6 +804,17 @@ class GenerateDocumentConfigurationComponent {
|
|
|
781
804
|
return '';
|
|
782
805
|
return ` (${entries.map(([k, v]) => `${k}=${v}`).join(', ')})`;
|
|
783
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* Creates a shared observable that resolves once with the prefill config
|
|
809
|
+
* (or null if no prefill is provided). This is used to seed the cascade
|
|
810
|
+
* with initial selection values before any loading starts.
|
|
811
|
+
*/
|
|
812
|
+
resolvePrefill$() {
|
|
813
|
+
if (!this.prefillConfiguration$) {
|
|
814
|
+
return of(null).pipe(shareReplay(1));
|
|
815
|
+
}
|
|
816
|
+
return this.prefillConfiguration$.pipe(take$1(1), shareReplay(1));
|
|
817
|
+
}
|
|
784
818
|
initContext() {
|
|
785
819
|
if (this.context$) {
|
|
786
820
|
this.context$.pipe(takeUntil(this.destroy$), filter(([context]) => context === 'case')).subscribe(([, params]) => {
|
|
@@ -789,35 +823,6 @@ class GenerateDocumentConfigurationComponent {
|
|
|
789
823
|
});
|
|
790
824
|
}
|
|
791
825
|
}
|
|
792
|
-
initPrefill() {
|
|
793
|
-
if (this.prefillConfiguration$) {
|
|
794
|
-
this.prefillConfiguration$.pipe(takeUntil(this.destroy$), filter(config => !!config?.templateId)).subscribe(config => {
|
|
795
|
-
this.selectedTemplateId$.next(config.templateId);
|
|
796
|
-
if (config.variantAttributes && (Array.isArray(config.variantAttributes) ? config.variantAttributes.length > 0 : Object.keys(config.variantAttributes).length > 0)) {
|
|
797
|
-
this.variantSelectionMode = 'attributes';
|
|
798
|
-
if (Array.isArray(config.variantAttributes)) {
|
|
799
|
-
// New format: VariantAttributeEntry[]
|
|
800
|
-
this.variantAttributeEntries = config.variantAttributes
|
|
801
|
-
.map(e => ({ key: e.key, value: e.value, required: e.required !== false }));
|
|
802
|
-
}
|
|
803
|
-
else {
|
|
804
|
-
// Old format: Record<string, string> — treat all as required
|
|
805
|
-
this.variantAttributeEntries = Object.entries(config.variantAttributes)
|
|
806
|
-
.map(([key, value]) => ({ key, value: String(value), required: true }));
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
else if (config.variantId) {
|
|
810
|
-
this.variantSelectionMode = 'explicit';
|
|
811
|
-
this.selectedVariantId$.next(config.variantId);
|
|
812
|
-
}
|
|
813
|
-
if (config.dataMapping) {
|
|
814
|
-
this.prefillDataMapping = config.dataMapping;
|
|
815
|
-
this.dataMapping$.next(config.dataMapping);
|
|
816
|
-
}
|
|
817
|
-
this.cdr.markForCheck();
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
826
|
initPluginConfiguration() {
|
|
822
827
|
const sources = [];
|
|
823
828
|
if (this.selectedPluginConfigurationData$) {
|
|
@@ -828,51 +833,88 @@ class GenerateDocumentConfigurationComponent {
|
|
|
828
833
|
this.pluginConfigurationId$.next(configurationId);
|
|
829
834
|
});
|
|
830
835
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
836
|
+
/**
|
|
837
|
+
* Sets up the entire reactive cascade:
|
|
838
|
+
*
|
|
839
|
+
* pluginConfigurationId$ → catalogs (+ environments independently)
|
|
840
|
+
* prefill + catalogs loaded → seed selectedCatalogId$
|
|
841
|
+
* selectedCatalogId$ → templates (+ attributes)
|
|
842
|
+
* prefill + templates loaded → seed selectedTemplateId$
|
|
843
|
+
* selectedTemplateId$ → variants + templateFields
|
|
844
|
+
* prefill + templateFields loaded → seed dataMapping
|
|
845
|
+
*/
|
|
846
|
+
initCascade() {
|
|
847
|
+
const configId$ = this.pluginConfigurationId$.pipe(filter(id => !!id), distinctUntilChanged());
|
|
848
|
+
// ── Catalogs: load when pluginConfigurationId changes ──
|
|
849
|
+
configId$.pipe(takeUntil(this.destroy$), tap(() => this.catalogs$.next(loadingResource(this.catalogs$.getValue().data))), switchMap(configurationId => this.epistolaPluginService.getCatalogs(configurationId).pipe(map(catalogs => successResource(catalogs.map(c => ({ id: c.id, text: c.name })))), catchError(() => of(errorResource([], 'Failed to load catalogs')))))).subscribe(resource => this.catalogs$.next(resource));
|
|
850
|
+
// ── Environments: load when pluginConfigurationId changes (independent) ──
|
|
851
|
+
configId$.pipe(takeUntil(this.destroy$), tap(() => this.environments$.next(loadingResource(this.environments$.getValue().data))), switchMap(configurationId => this.epistolaPluginService.getEnvironments(configurationId).pipe(map(envs => successResource(envs.map(e => ({ id: e.id, text: e.name })))), catchError(() => of(errorResource([], 'Failed to load environments')))))).subscribe(resource => this.environments$.next(resource));
|
|
852
|
+
// ── Seed selectedCatalogId$ from prefill once catalogs are loaded ──
|
|
853
|
+
combineLatest([
|
|
854
|
+
this.prefill$.pipe(filter(config => !!config?.catalogId)),
|
|
855
|
+
this.catalogs$.pipe(filter(c => !c.loading && c.data.length > 0))
|
|
856
|
+
]).pipe(takeUntil(this.destroy$), take$1(1)).subscribe(([config]) => {
|
|
857
|
+
this.selectedCatalogId$.next(config.catalogId);
|
|
845
858
|
});
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
859
|
+
// ── Templates: load when catalogId changes ──
|
|
860
|
+
const catalogId$ = this.selectedCatalogId$.pipe(filter(id => !!id), distinctUntilChanged());
|
|
861
|
+
combineLatest([configId$, catalogId$]).pipe(takeUntil(this.destroy$), tap(() => this.templates$.next(loadingResource(this.templates$.getValue().data))), switchMap(([configurationId, catalogId]) => this.epistolaPluginService.getTemplates(configurationId, catalogId).pipe(map(templates => successResource(templates.map(t => ({ id: t.id, text: t.name })))), catchError(() => of(errorResource([], 'Failed to load templates')))))).subscribe(resource => this.templates$.next(resource));
|
|
862
|
+
// ── Attributes: load when catalogId changes ──
|
|
863
|
+
combineLatest([configId$, catalogId$]).pipe(takeUntil(this.destroy$), switchMap(([configurationId, catalogId]) => this.epistolaPluginService.getAttributes(configurationId, catalogId).pipe(catchError(() => of([]))))).subscribe(attributes => {
|
|
849
864
|
this.availableAttributeKeys = attributes.map(a => a.key).sort();
|
|
850
865
|
this.cdr.markForCheck();
|
|
851
866
|
});
|
|
852
|
-
|
|
853
|
-
initVariantsLoading() {
|
|
867
|
+
// ── Seed selectedTemplateId$ from prefill once templates are loaded ──
|
|
854
868
|
combineLatest([
|
|
855
|
-
this.
|
|
856
|
-
this.
|
|
857
|
-
]).pipe(takeUntil(this.destroy$),
|
|
858
|
-
this.
|
|
859
|
-
return of(null);
|
|
860
|
-
}))), filter(result => result !== null)).subscribe(variants => {
|
|
861
|
-
this.variants$.next(successResource(variants.map(v => ({ id: v.id, text: v.name + this.formatAttributes(v.attributes) }))));
|
|
869
|
+
this.prefill$.pipe(filter(config => !!config?.templateId)),
|
|
870
|
+
this.templates$.pipe(filter(t => !t.loading && t.data.length > 0))
|
|
871
|
+
]).pipe(takeUntil(this.destroy$), take$1(1)).subscribe(([config]) => {
|
|
872
|
+
this.selectedTemplateId$.next(config.templateId);
|
|
862
873
|
});
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
combineLatest([
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
]).pipe(takeUntil(this.destroy$), filter(([configId, templateId]) => !!configId && !!templateId), tap(() => {
|
|
874
|
+
// ── Variants: load when templateId changes ──
|
|
875
|
+
const templateId$ = this.selectedTemplateId$.pipe(filter(id => !!id), distinctUntilChanged());
|
|
876
|
+
combineLatest([configId$, catalogId$, templateId$]).pipe(takeUntil(this.destroy$), tap(() => this.variants$.next(loadingResource(this.variants$.getValue().data))), switchMap(([configurationId, catalogId, templateId]) => this.epistolaPluginService.getVariants(configurationId, templateId, catalogId).pipe(map(variants => successResource(variants.map(v => ({ id: v.id, text: v.name + this.formatAttributes(v.attributes) })))), catchError(() => of(errorResource([], 'Failed to load variants')))))).subscribe(resource => this.variants$.next(resource));
|
|
877
|
+
// ── Template fields: load when templateId changes ──
|
|
878
|
+
combineLatest([configId$, catalogId$, templateId$]).pipe(takeUntil(this.destroy$), tap(() => {
|
|
869
879
|
this.templateFields$.next(loadingResource(this.templateFields$.getValue().data));
|
|
870
880
|
this.loadProcessVariables();
|
|
871
|
-
}), switchMap(([configurationId, templateId]) => this.epistolaPluginService.getTemplateDetails(configurationId, templateId).pipe(catchError(() =>
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
this.templateFields$.
|
|
881
|
+
}), switchMap(([configurationId, catalogId, templateId]) => this.epistolaPluginService.getTemplateDetails(configurationId, templateId, catalogId).pipe(map(details => successResource(details.fields || [])), catchError(() => of(errorResource([], 'Failed to load template fields')))))).subscribe(resource => this.templateFields$.next(resource));
|
|
882
|
+
// ── Seed variant + dataMapping from prefill once templateFields are loaded ──
|
|
883
|
+
combineLatest([
|
|
884
|
+
this.prefill$.pipe(filter(config => !!config?.templateId)),
|
|
885
|
+
this.templateFields$.pipe(filter(tf => !tf.loading && tf.data.length > 0))
|
|
886
|
+
]).pipe(takeUntil(this.destroy$), take$1(1)).subscribe(([config]) => {
|
|
887
|
+
if (!config)
|
|
888
|
+
return;
|
|
889
|
+
// Apply variant prefill
|
|
890
|
+
if (config.variantAttributes && (Array.isArray(config.variantAttributes) ? config.variantAttributes.length > 0 : Object.keys(config.variantAttributes).length > 0)) {
|
|
891
|
+
this.variantSelectionMode = 'attributes';
|
|
892
|
+
if (Array.isArray(config.variantAttributes)) {
|
|
893
|
+
this.variantAttributeEntries = config.variantAttributes
|
|
894
|
+
.map(e => ({ key: e.key, value: e.value, required: e.required !== false }));
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
this.variantAttributeEntries = Object.entries(config.variantAttributes)
|
|
898
|
+
.map(([key, value]) => ({ key, value: String(value), required: true }));
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
else if (config.variantId) {
|
|
902
|
+
this.variantSelectionMode = 'explicit';
|
|
903
|
+
this.selectedVariantId$.next(config.variantId);
|
|
904
|
+
}
|
|
905
|
+
// Apply dataMapping prefill — templateFields are guaranteed loaded at this point.
|
|
906
|
+
// Use setTimeout to ensure the tree component exists in the DOM (after *ngIf resolves)
|
|
907
|
+
// before setting the prefill, so ngOnChanges fires correctly on the child.
|
|
908
|
+
if (config.dataMapping) {
|
|
909
|
+
this.dataMapping$.next(config.dataMapping);
|
|
910
|
+
setTimeout(() => {
|
|
911
|
+
this.prefillDataMapping = { ...config.dataMapping };
|
|
912
|
+
this.cdr.detectChanges();
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
this.cdr.detectChanges();
|
|
917
|
+
}
|
|
876
918
|
});
|
|
877
919
|
}
|
|
878
920
|
loadProcessVariables() {
|
|
@@ -884,7 +926,8 @@ class GenerateDocumentConfigurationComponent {
|
|
|
884
926
|
}
|
|
885
927
|
}
|
|
886
928
|
handleValid(formValue) {
|
|
887
|
-
const baseComplete = !!(
|
|
929
|
+
const baseComplete = !!(this.selectedCatalogId$.getValue() &&
|
|
930
|
+
formValue?.templateId &&
|
|
888
931
|
formValue?.outputFormat &&
|
|
889
932
|
formValue?.filename &&
|
|
890
933
|
formValue?.resultProcessVariable);
|
|
@@ -904,8 +947,11 @@ class GenerateDocumentConfigurationComponent {
|
|
|
904
947
|
.pipe(take$1(1))
|
|
905
948
|
.subscribe(([formValue, valid, dataMapping]) => {
|
|
906
949
|
if (valid && formValue) {
|
|
950
|
+
const catalogId = this.selectedCatalogId$.getValue();
|
|
951
|
+
const templateId = formValue.templateId;
|
|
907
952
|
const config = {
|
|
908
|
-
|
|
953
|
+
catalogId,
|
|
954
|
+
templateId,
|
|
909
955
|
environmentId: formValue.environmentId || undefined,
|
|
910
956
|
dataMapping: dataMapping,
|
|
911
957
|
outputFormat: formValue.outputFormat,
|
|
@@ -927,7 +973,7 @@ class GenerateDocumentConfigurationComponent {
|
|
|
927
973
|
});
|
|
928
974
|
}
|
|
929
975
|
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 });
|
|
930
|
-
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 templates: templates$ | async,\n variants: variants$ | async,\n environments: environments$ | async,\n templateFields: templateFields$ | 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.templates.data\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templates.loading\"\n [required]=\"true\"\n [loading]=\"obs.templates.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.templates.error\" class=\"loading-error\">{{ obs.templates.error }}</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.variants.data\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variants.loading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variants.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.variants.error\" class=\"loading-error\">{{ obs.variants.error }}</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 <select\n *ngIf=\"!entry._customKey\"\n class=\"variant-attribute-input\"\n [ngModel]=\"entry.key\"\n (ngModelChange)=\"onKeySelected(entry, $event)\"\n [disabled]=\"obs.disabled\"\n >\n <option value=\"\" disabled>{{ 'attributeKey' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let key of availableAttributeKeys\" [value]=\"key\">{{ key }}</option>\n <option value=\"__custom__\">{{ 'attributeKeyCustom' | pluginTranslate: pluginId | async }}</option>\n </select>\n <div *ngIf=\"entry._customKey\" class=\"custom-key-input\">\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 <button type=\"button\" class=\"custom-key-cancel\" (click)=\"cancelCustomKey(entry)\" [disabled]=\"obs.disabled\">×</button>\n </div>\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 <label class=\"variant-attribute-required-toggle\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"entry.required\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <span class=\"required-label\">{{ (entry.required ? 'attributeRequired' : 'attributePreferred') | pluginTranslate: pluginId | async }}</span>\n </label>\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 >×</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.environments.data\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environments.loading\"\n [required]=\"false\"\n [loading]=\"obs.environments.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.environments.error\" class=\"loading-error\">{{ obs.environments.error }}</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=\"(templateFields$ | async)?.error as templateFieldsError\" class=\"loading-error\">{{ templateFieldsError }}</div>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields]=\"(templateFields$ | async)?.data ?? []\"\n [disabled]=\"!!(disabled$ | async)\"\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}.custom-key-input{display:flex;flex:1;gap:.25rem}.custom-key-input .variant-attribute-input{flex:1}.custom-key-cancel{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.custom-key-cancel:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.custom-key-cancel[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-required-toggle{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:#374151;white-space:nowrap;cursor:pointer}.variant-attribute-required-toggle input[type=checkbox]{margin:0;cursor:pointer}.variant-attribute-required-toggle .required-label{-webkit-user-select:none;user-select:none}.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.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { 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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { 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 });
|
|
976
|
+
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 catalogs: catalogs$ | async,\n templates: templates$ | async,\n variants: variants$ | async,\n environments: environments$ | async,\n templateFields: templateFields$ | async,\n selectedCatalogId: selectedCatalogId$ | async,\n selectedTemplateId: selectedTemplateId$ | async\n } as obs\"\n>\n <v-select\n name=\"catalogId\"\n [title]=\"'catalogId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'catalogIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.catalogs.data\"\n [defaultSelectionId]=\"obs.prefill?.catalogId\"\n [disabled]=\"obs.disabled || obs.catalogs.loading\"\n [required]=\"true\"\n [loading]=\"obs.catalogs.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.catalogs.error\" class=\"loading-error\">{{ obs.catalogs.error }}</div>\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.templates.data\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templates.loading || !obs.selectedCatalogId\"\n [required]=\"true\"\n [loading]=\"obs.templates.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.templates.error\" class=\"loading-error\">{{ obs.templates.error }}</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.variants.data\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variants.loading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variants.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.variants.error\" class=\"loading-error\">{{ obs.variants.error }}</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 <select\n *ngIf=\"!entry._customKey\"\n class=\"variant-attribute-input\"\n [ngModel]=\"entry.key\"\n (ngModelChange)=\"onKeySelected(entry, $event)\"\n [disabled]=\"obs.disabled\"\n >\n <option value=\"\" disabled>{{ 'attributeKey' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let key of availableAttributeKeys\" [value]=\"key\">{{ key }}</option>\n <option value=\"__custom__\">{{ 'attributeKeyCustom' | pluginTranslate: pluginId | async }}</option>\n </select>\n <div *ngIf=\"entry._customKey\" class=\"custom-key-input\">\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 <button type=\"button\" class=\"custom-key-cancel\" (click)=\"cancelCustomKey(entry)\" [disabled]=\"obs.disabled\">×</button>\n </div>\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 <label class=\"variant-attribute-required-toggle\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"entry.required\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <span class=\"required-label\">{{ (entry.required ? 'attributeRequired' : 'attributePreferred') | pluginTranslate: pluginId | async }}</span>\n </label>\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 >×</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.environments.data\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environments.loading\"\n [required]=\"false\"\n [loading]=\"obs.environments.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.environments.error\" class=\"loading-error\">{{ obs.environments.error }}</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=\"(templateFields$ | async)?.error as templateFieldsError\" class=\"loading-error\">{{ templateFieldsError }}</div>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields]=\"(templateFields$ | async)?.data ?? []\"\n [disabled]=\"!!(disabled$ | async)\"\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}.custom-key-input{display:flex;flex:1;gap:.25rem}.custom-key-input .variant-attribute-input{flex:1}.custom-key-cancel{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.custom-key-cancel:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.custom-key-cancel[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-required-toggle{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:#374151;white-space:nowrap;cursor:pointer}.variant-attribute-required-toggle input[type=checkbox]{margin:0;cursor:pointer}.variant-attribute-required-toggle .required-label{-webkit-user-select:none;user-select:none}.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.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { 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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { 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 });
|
|
931
977
|
}
|
|
932
978
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GenerateDocumentConfigurationComponent, decorators: [{
|
|
933
979
|
type: Component,
|
|
@@ -939,7 +985,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
939
985
|
InputModule,
|
|
940
986
|
SelectModule,
|
|
941
987
|
DataMappingTreeComponent
|
|
942
|
-
], template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: disabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null,\n templates: templates$ | async,\n variants: variants$ | async,\n environments: environments$ | async,\n templateFields: templateFields$ | 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.templates.data\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templates.loading\"\n [required]=\"true\"\n [loading]=\"obs.templates.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.templates.error\" class=\"loading-error\">{{ obs.templates.error }}</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.variants.data\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variants.loading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variants.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.variants.error\" class=\"loading-error\">{{ obs.variants.error }}</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 <select\n *ngIf=\"!entry._customKey\"\n class=\"variant-attribute-input\"\n [ngModel]=\"entry.key\"\n (ngModelChange)=\"onKeySelected(entry, $event)\"\n [disabled]=\"obs.disabled\"\n >\n <option value=\"\" disabled>{{ 'attributeKey' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let key of availableAttributeKeys\" [value]=\"key\">{{ key }}</option>\n <option value=\"__custom__\">{{ 'attributeKeyCustom' | pluginTranslate: pluginId | async }}</option>\n </select>\n <div *ngIf=\"entry._customKey\" class=\"custom-key-input\">\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 <button type=\"button\" class=\"custom-key-cancel\" (click)=\"cancelCustomKey(entry)\" [disabled]=\"obs.disabled\">×</button>\n </div>\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 <label class=\"variant-attribute-required-toggle\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"entry.required\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <span class=\"required-label\">{{ (entry.required ? 'attributeRequired' : 'attributePreferred') | pluginTranslate: pluginId | async }}</span>\n </label>\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 >×</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.environments.data\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environments.loading\"\n [required]=\"false\"\n [loading]=\"obs.environments.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.environments.error\" class=\"loading-error\">{{ obs.environments.error }}</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=\"(templateFields$ | async)?.error as templateFieldsError\" class=\"loading-error\">{{ templateFieldsError }}</div>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields]=\"(templateFields$ | async)?.data ?? []\"\n [disabled]=\"!!(disabled$ | async)\"\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}.custom-key-input{display:flex;flex:1;gap:.25rem}.custom-key-input .variant-attribute-input{flex:1}.custom-key-cancel{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.custom-key-cancel:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.custom-key-cancel[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-required-toggle{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:#374151;white-space:nowrap;cursor:pointer}.variant-attribute-required-toggle input[type=checkbox]{margin:0;cursor:pointer}.variant-attribute-required-toggle .required-label{-webkit-user-select:none;user-select:none}.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"] }]
|
|
988
|
+
], template: "<v-form\n (valueChange)=\"formValueChange($event)\"\n *ngIf=\"{\n disabled: disabled$ | async,\n prefill: prefillConfiguration$ ? (prefillConfiguration$ | async) : null,\n catalogs: catalogs$ | async,\n templates: templates$ | async,\n variants: variants$ | async,\n environments: environments$ | async,\n templateFields: templateFields$ | async,\n selectedCatalogId: selectedCatalogId$ | async,\n selectedTemplateId: selectedTemplateId$ | async\n } as obs\"\n>\n <v-select\n name=\"catalogId\"\n [title]=\"'catalogId' | pluginTranslate: pluginId | async\"\n [tooltip]=\"'catalogIdTooltip' | pluginTranslate: pluginId | async\"\n [margin]=\"true\"\n [items]=\"obs.catalogs.data\"\n [defaultSelectionId]=\"obs.prefill?.catalogId\"\n [disabled]=\"obs.disabled || obs.catalogs.loading\"\n [required]=\"true\"\n [loading]=\"obs.catalogs.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.catalogs.error\" class=\"loading-error\">{{ obs.catalogs.error }}</div>\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.templates.data\"\n [defaultSelectionId]=\"obs.prefill?.templateId\"\n [disabled]=\"obs.disabled || obs.templates.loading || !obs.selectedCatalogId\"\n [required]=\"true\"\n [loading]=\"obs.templates.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.templates.error\" class=\"loading-error\">{{ obs.templates.error }}</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.variants.data\"\n [defaultSelectionId]=\"obs.prefill?.variantId\"\n [disabled]=\"obs.disabled || obs.variants.loading || !obs.selectedTemplateId\"\n [required]=\"false\"\n [loading]=\"obs.variants.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.variants.error\" class=\"loading-error\">{{ obs.variants.error }}</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 <select\n *ngIf=\"!entry._customKey\"\n class=\"variant-attribute-input\"\n [ngModel]=\"entry.key\"\n (ngModelChange)=\"onKeySelected(entry, $event)\"\n [disabled]=\"obs.disabled\"\n >\n <option value=\"\" disabled>{{ 'attributeKey' | pluginTranslate: pluginId | async }}</option>\n <option *ngFor=\"let key of availableAttributeKeys\" [value]=\"key\">{{ key }}</option>\n <option value=\"__custom__\">{{ 'attributeKeyCustom' | pluginTranslate: pluginId | async }}</option>\n </select>\n <div *ngIf=\"entry._customKey\" class=\"custom-key-input\">\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 <button type=\"button\" class=\"custom-key-cancel\" (click)=\"cancelCustomKey(entry)\" [disabled]=\"obs.disabled\">×</button>\n </div>\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 <label class=\"variant-attribute-required-toggle\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"entry.required\"\n (ngModelChange)=\"onAttributeEntryChange()\"\n [disabled]=\"obs.disabled\"\n />\n <span class=\"required-label\">{{ (entry.required ? 'attributeRequired' : 'attributePreferred') | pluginTranslate: pluginId | async }}</span>\n </label>\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 >×</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.environments.data\"\n [defaultSelectionId]=\"obs.prefill?.environmentId\"\n [disabled]=\"obs.disabled || obs.environments.loading\"\n [required]=\"false\"\n [loading]=\"obs.environments.loading\"\n >\n </v-select>\n <div *ngIf=\"obs.environments.error\" class=\"loading-error\">{{ obs.environments.error }}</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=\"(templateFields$ | async)?.error as templateFieldsError\" class=\"loading-error\">{{ templateFieldsError }}</div>\n\n<epistola-data-mapping-tree\n *ngIf=\"(selectedTemplateId$ | async)\"\n [pluginId]=\"pluginId\"\n [templateFields]=\"(templateFields$ | async)?.data ?? []\"\n [disabled]=\"!!(disabled$ | async)\"\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}.custom-key-input{display:flex;flex:1;gap:.25rem}.custom-key-input .variant-attribute-input{flex:1}.custom-key-cancel{padding:.25rem .5rem;font-size:1rem;line-height:1;background:none;border:1px solid #d1d5db;border-radius:4px;cursor:pointer;color:#6b7280}.custom-key-cancel:hover:not([disabled]){color:#dc3545;border-color:#dc3545}.custom-key-cancel[disabled]{opacity:.5;cursor:not-allowed}.variant-attribute-required-toggle{display:flex;align-items:center;gap:.25rem;font-size:.75rem;color:#374151;white-space:nowrap;cursor:pointer}.variant-attribute-required-toggle input[type=checkbox]{margin:0;cursor:pointer}.variant-attribute-required-toggle .required-label{-webkit-user-select:none;user-select:none}.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"] }]
|
|
943
989
|
}], ctorParameters: () => [{ type: EpistolaPluginService }, { type: i2$2.ProcessLinkStateService }, { type: i0.ChangeDetectorRef }], propDecorators: { save$: [{
|
|
944
990
|
type: Input
|
|
945
991
|
}], disabled$: [{
|
|
@@ -1991,6 +2037,8 @@ const epistolaPluginSpecification = {
|
|
|
1991
2037
|
templateSyncEnabled: 'Template synchronisatie',
|
|
1992
2038
|
templateSyncEnabledTooltip: 'Synchroniseer template definities automatisch van het classpath naar Epistola bij het opstarten',
|
|
1993
2039
|
'generate-document': 'Genereer Document',
|
|
2040
|
+
catalogId: 'Catalogus',
|
|
2041
|
+
catalogIdTooltip: 'Selecteer de catalogus waaruit een template gekozen wordt',
|
|
1994
2042
|
templateId: 'Template',
|
|
1995
2043
|
templateIdTooltip: 'Selecteer het template dat gebruikt wordt voor documentgeneratie',
|
|
1996
2044
|
variantId: 'Variant',
|
|
@@ -2080,6 +2128,8 @@ const epistolaPluginSpecification = {
|
|
|
2080
2128
|
templateSyncEnabled: 'Template sync',
|
|
2081
2129
|
templateSyncEnabledTooltip: 'Automatically synchronize template definitions from classpath to Epistola on startup',
|
|
2082
2130
|
'generate-document': 'Generate Document',
|
|
2131
|
+
catalogId: 'Catalog',
|
|
2132
|
+
catalogIdTooltip: 'Select the catalog to choose a template from',
|
|
2083
2133
|
templateId: 'Template',
|
|
2084
2134
|
templateIdTooltip: 'Select the template to use for document generation',
|
|
2085
2135
|
variantId: 'Variant',
|