@epistola.app/valtimo-plugin 0.10.0 → 0.11.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 { EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
- import { FunctionConfigurationComponent } from '@valtimo/plugin';
2
+ import { FunctionConfigurationComponent, FunctionConfigurationData } from '@valtimo/plugin';
3
3
  import { FormOutput } from '@valtimo/components';
4
4
  import { BehaviorSubject, Observable } from 'rxjs';
5
5
  import { CheckJobStatusConfig } from '../../models';
@@ -10,7 +10,7 @@ export declare class CheckJobStatusConfigurationComponent implements FunctionCon
10
10
  pluginId: string;
11
11
  prefillConfiguration$: Observable<CheckJobStatusConfig>;
12
12
  valid: EventEmitter<boolean>;
13
- configuration: EventEmitter<CheckJobStatusConfig>;
13
+ configuration: EventEmitter<FunctionConfigurationData>;
14
14
  private saveSubscription;
15
15
  private readonly formValue$;
16
16
  private readonly valid$;
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
- import { FunctionConfigurationComponent } from '@valtimo/plugin';
2
+ import { FunctionConfigurationComponent, FunctionConfigurationData } from '@valtimo/plugin';
3
3
  import { FormOutput, SelectItem } from '@valtimo/components';
4
4
  import { BehaviorSubject, Observable } from 'rxjs';
5
5
  import { DownloadDocumentConfig } from '../../models';
@@ -10,7 +10,7 @@ export declare class DownloadDocumentConfigurationComponent implements FunctionC
10
10
  pluginId: string;
11
11
  prefillConfiguration$: Observable<DownloadDocumentConfig>;
12
12
  valid: EventEmitter<boolean>;
13
- configuration: EventEmitter<DownloadDocumentConfig>;
13
+ configuration: EventEmitter<FunctionConfigurationData>;
14
14
  private saveSubscription;
15
15
  private readonly formValue$;
16
16
  private readonly valid$;
@@ -1,7 +1,7 @@
1
1
  import { OnInit } from '@angular/core';
2
2
  import { ActivatedRoute, Router } from '@angular/router';
3
3
  import { EpistolaAdminService } from '../../services/epistola-admin.service';
4
- import { BpmnValidationReport, BpmnValidationViolation, ChangelogRelease, ClasspathCatalog, FormCarrierIssue, PendingJob, PluginUsageEntry } from '../../models';
4
+ import { BpmnValidationReport, BpmnValidationViolation, ChangelogRelease, ClasspathCatalog, FormCarrierIssue, LegacyOverrideForm, PendingJob, PluginUsageEntry } from '../../models';
5
5
  import * as i0 from "@angular/core";
6
6
  /**
7
7
  * Combined view model for a single plugin configuration card.
@@ -55,6 +55,8 @@ export declare class EpistolaAdminPageComponent implements OnInit {
55
55
  type: 'success' | 'error';
56
56
  message: string;
57
57
  } | null;
58
+ legacyOverrideForms: LegacyOverrideForm[] | null;
59
+ legacyOverrideLoading: boolean;
58
60
  private connectionStatuses;
59
61
  private usageEntries;
60
62
  private pendingJobs;
@@ -67,11 +69,16 @@ export declare class EpistolaAdminPageComponent implements OnInit {
67
69
  get validationViolations(): BpmnValidationViolation[];
68
70
  /** Scan cadence in whole minutes, for the "refreshes every N min" note. */
69
71
  get refreshIntervalMinutes(): number;
72
+ /** Combined "forms needing attention" count for the tab badge (carrier + legacy override). */
73
+ get formsAttentionCount(): number;
74
+ /** Whether the forms tab has loaded at least one of its two scans. */
75
+ get formsScanLoaded(): boolean;
70
76
  ngOnInit(): void;
71
77
  selectConfiguration(card: ConfigurationCard): void;
72
78
  backToOverview(): void;
73
79
  setActiveTab(tab: 'actions' | 'pending' | 'catalogs'): void;
74
80
  setOverviewTab(tab: 'configurations' | 'validations' | 'changelog' | 'forms'): void;
81
+ private loadLegacyOverrideForms;
75
82
  private loadFormIssues;
76
83
  isRepairingForm(issue: FormCarrierIssue): boolean;
77
84
  repairForm(issue: FormCarrierIssue): void;
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
- import { PluginConfigurationComponent } from '@valtimo/plugin';
2
+ import { PluginConfigurationComponent, PluginConfigurationData } from '@valtimo/plugin';
3
3
  import { FormOutput } from '@valtimo/components';
4
4
  import { Observable } from 'rxjs';
5
5
  import { EpistolaPluginConfig } from '../../models';
@@ -10,7 +10,7 @@ export declare class EpistolaConfigurationComponent implements PluginConfigurati
10
10
  pluginId: string;
11
11
  prefillConfiguration$: Observable<EpistolaPluginConfig>;
12
12
  valid: EventEmitter<boolean>;
13
- configuration: EventEmitter<EpistolaPluginConfig>;
13
+ configuration: EventEmitter<PluginConfigurationData>;
14
14
  /** Epistola slug pattern: lowercase alphanumeric with hyphens, no leading/trailing hyphens. */
15
15
  private static readonly SLUG_PATTERN;
16
16
  private saveSubscription;
@@ -14,12 +14,42 @@ export declare class EpistolaDocumentPreviewComponent implements FormioCustomCom
14
14
  label: string;
15
15
  processDefinitionKey?: string;
16
16
  sourceActivityId?: string;
17
- overrideMapping?: Record<string, any>;
17
+ /**
18
+ * The override mapping: a JSONata expression string over `$form`, or — for
19
+ * not-yet-re-saved forms — the legacy `form:`-ref object.
20
+ */
21
+ overrideMapping?: string | Record<string, any>;
18
22
  /**
19
23
  * Task id forwarded by the Formio wrapper from the server-prefilled form
20
24
  * ({@code epistola:taskId} value resolver), populated in every Valtimo task-open flow.
21
25
  */
22
26
  taskInstanceId?: string | null;
27
+ /**
28
+ * The computed input overrides (`{ doc, pv }`) the preview renders with, pushed
29
+ * by the Formio wrapper. Kept separate from the Formio `value`: Valtimo's custom
30
+ * component bridge only mirrors `value` to the DOM (never to Formio's data
31
+ * model), so Formio resets it to `emptyValue` on every redraw — which would
32
+ * cancel the preview. This dedicated input is never touched by Formio.
33
+ */
34
+ inputOverrides?: Record<string, any> | null;
35
+ /**
36
+ * Forces the Formio wrapper to recompute the input overrides from the live form
37
+ * data. Set by the wrapper for override-driven previews; lets the Refresh button
38
+ * work before the first change (e.g. on initial load with pre-filled fields).
39
+ */
40
+ requestOverrides?: () => void;
41
+ /**
42
+ * Current auto-refresh state, forwarded by the wrapper (seeded from the builder's
43
+ * `autoRefresh` option, default on). Seeds the header toggle's initial state.
44
+ */
45
+ autoRefresh?: boolean;
46
+ /**
47
+ * Tells the wrapper to enable/disable auto-refresh (recompute on change/blur).
48
+ * Set by the wrapper for override-driven previews; called by the header toggle.
49
+ */
50
+ setAutoRefresh?: (enabled: boolean) => void;
51
+ /** Runtime state of the header auto-refresh toggle. */
52
+ autoRefreshEnabled: boolean;
23
53
  loading: boolean;
24
54
  error: string | null;
25
55
  previewUrl: SafeResourceUrl | null;
@@ -34,14 +64,16 @@ export declare class EpistolaDocumentPreviewComponent implements FormioCustomCom
34
64
  * (e.g. Formio builder), in which case the component fails closed.
35
65
  */
36
66
  private get currentTaskId();
37
- get overrideMappingScopes(): string[];
38
- overrideMappingEntries(scope: string): {
39
- path: string;
40
- field: string;
41
- }[];
67
+ /**
68
+ * The override mapping as a JSONata expression for the design-mode summary.
69
+ * Legacy `form:`-ref objects are converted on the fly for display.
70
+ */
71
+ get overrideExpression(): string;
42
72
  ngOnChanges(changes: SimpleChanges): void;
43
73
  ngOnDestroy(): void;
44
74
  refresh(): void;
75
+ /** Toggle auto-refresh for this session; flipping it on triggers an immediate refresh. */
76
+ onToggleAutoRefresh(event: Event): void;
45
77
  /**
46
78
  * Load the preview only when there is enough data for it. Override-driven
47
79
  * previews (those with an override mapping) wait until the mapped form data
@@ -60,5 +92,5 @@ export declare class EpistolaDocumentPreviewComponent implements FormioCustomCom
60
92
  private handlePreviewError;
61
93
  private revokeBlobUrl;
62
94
  static ɵfac: i0.ɵɵFactoryDeclaration<EpistolaDocumentPreviewComponent, never>;
63
- static ɵcmp: i0.ɵɵComponentDeclaration<EpistolaDocumentPreviewComponent, "epistola-document-preview-component", never, { "value": { "alias": "value"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "label": { "alias": "label"; "required": false; }; "processDefinitionKey": { "alias": "processDefinitionKey"; "required": false; }; "sourceActivityId": { "alias": "sourceActivityId"; "required": false; }; "overrideMapping": { "alias": "overrideMapping"; "required": false; }; "taskInstanceId": { "alias": "taskInstanceId"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
95
+ static ɵcmp: i0.ɵɵComponentDeclaration<EpistolaDocumentPreviewComponent, "epistola-document-preview-component", never, { "value": { "alias": "value"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "label": { "alias": "label"; "required": false; }; "processDefinitionKey": { "alias": "processDefinitionKey"; "required": false; }; "sourceActivityId": { "alias": "sourceActivityId"; "required": false; }; "overrideMapping": { "alias": "overrideMapping"; "required": false; }; "taskInstanceId": { "alias": "taskInstanceId"; "required": false; }; "inputOverrides": { "alias": "inputOverrides"; "required": false; }; "requestOverrides": { "alias": "requestOverrides"; "required": false; }; "autoRefresh": { "alias": "autoRefresh"; "required": false; }; "setAutoRefresh": { "alias": "setAutoRefresh"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
64
96
  }
@@ -1,5 +1,10 @@
1
- import { OverrideMapping } from '../override-builder/override-builder.component';
2
- export declare const FORM_REF_PREFIX = "form:";
1
+ /** Re-exported for backward compatibility with existing imports/tests. */
2
+ export { FORM_REF_PREFIX } from '../override-builder/legacy-override-converter';
3
+ /**
4
+ * An override mapping is either the new JSONata expression **string** (over
5
+ * `$form`) or — for not-yet-re-saved forms — the legacy `form:`-ref **object**.
6
+ */
7
+ export type OverrideMappingValue = string | Record<string, any> | null | undefined;
3
8
  /**
4
9
  * Detect if a string value is a JSONata expression (vs a plain literal).
5
10
  * Checks for characters that indicate JSONata operators: $, &, (, {, ?, [
@@ -16,7 +21,7 @@ export declare function expandDotNotation(flat: Record<string, any>): Record<str
16
21
  * before it can render. Previews without a mapping load straight from the base
17
22
  * doc/case data.
18
23
  */
19
- export declare function isOverrideDriven(mapping?: OverrideMapping | null): boolean;
24
+ export declare function isOverrideDriven(mapping?: OverrideMappingValue): boolean;
20
25
  /**
21
26
  * Whether the computed input overrides carry any usable data yet.
22
27
  */
@@ -31,10 +36,16 @@ export declare function hasUsableOverrides(overrides?: Record<string, any> | nul
31
36
  * required fields).
32
37
  * - Previews without a mapping always load (base data is the whole input).
33
38
  */
34
- export declare function shouldLoadPreview(mapping?: OverrideMapping | null, overrides?: Record<string, any> | null): boolean;
39
+ export declare function shouldLoadPreview(mapping?: OverrideMappingValue, overrides?: Record<string, any> | null): boolean;
35
40
  /**
36
- * Given an override mapping (scope -> { inputPath -> "form:<componentKey>" })
37
- * and form data, produce the inputOverrides object for the backend.
38
- * The "form:" prefix identifies form field references; the remainder is the Formio component key.
41
+ * Given an override mapping and the live form data, produce the inputOverrides
42
+ * object (`{ doc, pv }`) the backend overlays onto the real document / process
43
+ * variables before the data mapping runs.
44
+ *
45
+ * The mapping is a JSONata expression over `$form`; legacy `form:`-ref objects
46
+ * are converted on the fly via {@link legacyOverrideToJsonata}. Evaluation is
47
+ * asynchronous because `jsonata().evaluate()` returns a Promise. Only `doc` and
48
+ * `pv` scopes (with at least one resolved field) are kept — matching what the
49
+ * backend consumes.
39
50
  */
40
- export declare function computeInputOverrides(mapping: OverrideMapping, formData: Record<string, any>): Record<string, any>;
51
+ export declare function computeInputOverrides(mapping: OverrideMappingValue, formData: Record<string, any>): Promise<Record<string, any>>;
@@ -1,5 +1,5 @@
1
1
  import { ChangeDetectorRef, EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
- import { FunctionConfigurationComponent, PluginConfigurationData } from '@valtimo/plugin';
2
+ import { FunctionConfigurationComponent, FunctionConfigurationData, PluginConfigurationData } from '@valtimo/plugin';
3
3
  import { FormOutput, SelectedValue, SelectItem } from '@valtimo/components';
4
4
  import { CaseManagementParams, ManagementContext } from '@valtimo/shared';
5
5
  import { ProcessLinkStateService } from '@valtimo/process-link';
@@ -19,7 +19,7 @@ export declare class GenerateDocumentConfigurationComponent implements FunctionC
19
19
  selectedPluginConfigurationData$?: Observable<PluginConfigurationData>;
20
20
  context$?: Observable<[ManagementContext, CaseManagementParams]>;
21
21
  valid: EventEmitter<boolean>;
22
- configuration: EventEmitter<GenerateDocumentConfig>;
22
+ configuration: EventEmitter<FunctionConfigurationData>;
23
23
  catalogs$: BehaviorSubject<AsyncResource<SelectItem[]>>;
24
24
  templates$: BehaviorSubject<AsyncResource<SelectItem[]>>;
25
25
  variants$: BehaviorSubject<AsyncResource<SelectItem[]>>;
@@ -68,6 +68,8 @@ export declare class GenerateDocumentConfigurationComponent implements FunctionC
68
68
  processVariables: string[];
69
69
  expressionFunctions: ExpressionFunctionInfo[];
70
70
  variableSuggestions: VariableSuggestions | null;
71
+ /** Context variables for the JSONata editor's autocomplete ($doc/$pv/$case). */
72
+ editorContextVariables: Record<string, string[]>;
71
73
  prefillDataMapping: Record<string, any>;
72
74
  validationErrors$: BehaviorSubject<JsonataFieldError[]>;
73
75
  private readonly destroy$;
@@ -1,11 +1,19 @@
1
1
  import { EventEmitter, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
2
- import { ExpressionFunctionInfo, VariableSuggestions } from '../../models';
2
+ import { ExpressionFunctionInfo } from '../../models';
3
3
  import * as i0 from "@angular/core";
4
4
  export declare class JsonataEditorComponent implements OnChanges, OnDestroy {
5
5
  expression: string;
6
6
  disabled: boolean;
7
- suggestions: VariableSuggestions | null;
7
+ /**
8
+ * Context variables in scope, keyed by name (without `$`), each mapping to its
9
+ * field/path suggestions — e.g. `{ doc: [...], pv: [...] }` for the data
10
+ * mapping, `{ form: [...] }` for the override builder. Drives both the
11
+ * `$`-variable list and `$<name>.` field completion.
12
+ */
13
+ contextVariables: Record<string, string[]>;
8
14
  functions: ExpressionFunctionInfo[];
15
+ /** Footer hint listing the context variables in scope. */
16
+ variablesHint: string;
9
17
  expressionChange: EventEmitter<string>;
10
18
  validChange: EventEmitter<boolean>;
11
19
  editorModel: {
@@ -25,5 +33,5 @@ export declare class JsonataEditorComponent implements OnChanges, OnDestroy {
25
33
  private tryRegisterLanguage;
26
34
  private validateExpression;
27
35
  static ɵfac: i0.ɵɵFactoryDeclaration<JsonataEditorComponent, never>;
28
- static ɵcmp: i0.ɵɵComponentDeclaration<JsonataEditorComponent, "epistola-jsonata-editor", never, { "expression": { "alias": "expression"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "suggestions": { "alias": "suggestions"; "required": false; }; "functions": { "alias": "functions"; "required": false; }; }, { "expressionChange": "expressionChange"; "validChange": "validChange"; }, never, never, true, never>;
36
+ static ɵcmp: i0.ɵɵComponentDeclaration<JsonataEditorComponent, "epistola-jsonata-editor", never, { "expression": { "alias": "expression"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "contextVariables": { "alias": "contextVariables"; "required": false; }; "functions": { "alias": "functions"; "required": false; }; "variablesHint": { "alias": "variablesHint"; "required": false; }; }, { "expressionChange": "expressionChange"; "validChange": "validChange"; }, never, never, true, never>;
29
37
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Prefix that marked a form-field reference in the legacy override-mapping
3
+ * object format (e.g. `"form:motivationField"`).
4
+ */
5
+ export declare const FORM_REF_PREFIX = "form:";
6
+ /**
7
+ * Whether a stored override-mapping value is in the legacy **object** format
8
+ * (`{ scope: { inputPath: "form:fieldKey" } }`) rather than the new JSONata
9
+ * **string** format.
10
+ */
11
+ export declare function isLegacyOverrideMapping(value: unknown): value is Record<string, any>;
12
+ /**
13
+ * TEMPORARY migration shim.
14
+ *
15
+ * Converts a legacy override-mapping object into the equivalent JSONata string
16
+ * over `$form`. Funnelling every legacy value through this one function keeps
17
+ * the rest of the codebase JSONata-only.
18
+ *
19
+ * @deprecated Remove once all deployed forms have been re-saved in the JSONata
20
+ * format. The admin page's "legacy override format" warning tracks which
21
+ * forms still need migrating.
22
+ */
23
+ export declare function legacyOverrideToJsonata(mapping: Record<string, any>): string;
@@ -1,42 +1,74 @@
1
- import { ChangeDetectorRef, EventEmitter } from '@angular/core';
1
+ import { ChangeDetectorRef, EventEmitter, OnDestroy, SimpleChanges } from '@angular/core';
2
2
  import { FormioCustomComponent } from '@valtimo/components';
3
+ import { OverrideRow } from './override-jsonata';
4
+ import { EpistolaPluginService } from '../../services';
5
+ import { ReferencedPath } from '../../utils/extract-referenced-paths';
3
6
  import * as i0 from "@angular/core";
4
- interface OverrideRow {
5
- scope: 'doc' | 'pv';
6
- inputPath: string;
7
- formFieldKey: string;
8
- }
9
7
  export interface FormFieldOption {
10
8
  key: string;
11
9
  label: string;
12
10
  }
13
11
  /**
14
- * Override mapping format: scope { inputPath → "form:<componentKey>" }
15
- * The "form:" prefix identifies this as a reference to a Formio component.
12
+ * Override mapping value: a JSONata expression (over `$form`) that produces the
13
+ * `{ doc, pv }` overlay applied during preview. Legacy form definitions may
14
+ * still carry the old `{ scope: { inputPath: "form:key" } }` object; it is
15
+ * converted to JSONata on load (see {@link legacyOverrideToJsonata}).
16
16
  */
17
17
  export type OverrideMapping = Record<string, Record<string, string>>;
18
- export declare class EpistolaOverrideBuilderComponent implements FormioCustomComponent<OverrideMapping | null> {
18
+ export declare class EpistolaOverrideBuilderComponent implements FormioCustomComponent<string | OverrideMapping | null>, OnDestroy {
19
19
  private readonly cdr;
20
- value: OverrideMapping | null;
21
- valueChange: EventEmitter<OverrideMapping>;
20
+ private readonly pluginService;
21
+ value: string | OverrideMapping | null;
22
+ valueChange: EventEmitter<string | OverrideMapping>;
22
23
  disabled: boolean;
23
24
  label: string;
24
25
  availableFields: FormFieldOption[];
26
+ /**
27
+ * Identify the selected generate-document process link, forwarded from the
28
+ * preview component's editForm. Used to fetch the link's data mapping and
29
+ * surface which `$doc`/`$pv` paths it consumes — purely informational guidance.
30
+ */
31
+ processDefinitionKey: string;
32
+ sourceActivityId: string;
25
33
  rows: OverrideRow[];
26
34
  advancedMode: boolean;
27
- jsonText: string;
28
- jsonError: string | null;
35
+ /** True when the current expression can't be represented by the simple table. */
36
+ simpleUnavailable: boolean;
37
+ expression: string;
38
+ /** `$doc`/`$pv`/`$case` paths the selected template's data mapping references. */
39
+ referencedPaths: ReferencedPath[];
40
+ readonly exampleExpression = "{ \"doc\": { \"naam\": $form.voornaam & ' ' & $form.achternaam } }";
29
41
  private initialized;
30
- constructor(cdr: ChangeDetectorRef);
31
- ngOnChanges(): void;
42
+ private readonly destroy$;
43
+ /** Link last fetched, so we refetch only when the selected process link changes. */
44
+ private lastFetchedLinkKey;
45
+ constructor(cdr: ChangeDetectorRef, pluginService: EpistolaPluginService);
46
+ get formFieldKeys(): string[];
47
+ get hasReferencedPaths(): boolean;
48
+ /** Referenced paths for a scope, excluding whole-scope refs (empty path) that aren't completions. */
49
+ referencedPathsForScope(scope: ReferencedPath['scope']): string[];
50
+ /** Autocomplete context for the advanced editor: form fields plus the mapping's referenced paths. */
51
+ get editorContextVariables(): Record<string, string[]>;
52
+ /** Render a referenced path as a `$scope.path` reference (or `$scope` for a whole-scope ref). */
53
+ formatReferencedPath(ref: ReferencedPath): string;
54
+ ngOnChanges(_changes?: SimpleChanges): void;
55
+ ngOnDestroy(): void;
56
+ /**
57
+ * Fetch the selected process link's data mapping and extract the `$doc`/`$pv`/`$case`
58
+ * paths it references, so the author sees what this template consumes. Refetches only
59
+ * when the selected link changes; clears when no link is selected. Best-effort and
60
+ * non-blocking — a failed fetch simply shows no suggestions.
61
+ */
62
+ private refreshReferencedPaths;
32
63
  toggleMode(): void;
33
64
  addRow(): void;
34
65
  removeRow(index: number): void;
66
+ /** Simple-table change: serialize rows back to a JSONata expression. */
35
67
  emitChange(): void;
36
- onJsonChange(text: string): void;
37
- private rowsToMapping;
38
- private mappingToRows;
68
+ /** Advanced-editor change. */
69
+ onExpressionChange(expr: string): void;
70
+ private loadFromExpression;
71
+ private emit;
39
72
  static ɵfac: i0.ɵɵFactoryDeclaration<EpistolaOverrideBuilderComponent, never>;
40
- static ɵcmp: i0.ɵɵComponentDeclaration<EpistolaOverrideBuilderComponent, "epistola-override-builder-component", never, { "value": { "alias": "value"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "label": { "alias": "label"; "required": false; }; "availableFields": { "alias": "availableFields"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
73
+ static ɵcmp: i0.ɵɵComponentDeclaration<EpistolaOverrideBuilderComponent, "epistola-override-builder-component", never, { "value": { "alias": "value"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "label": { "alias": "label"; "required": false; }; "availableFields": { "alias": "availableFields"; "required": false; }; "processDefinitionKey": { "alias": "processDefinitionKey"; "required": false; }; "sourceActivityId": { "alias": "sourceActivityId"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
41
74
  }
42
- export {};
@@ -0,0 +1,25 @@
1
+ /**
2
+ * A single row in the override builder's simple table: a form field feeding a
3
+ * `doc`/`pv` input path during preview.
4
+ */
5
+ export interface OverrideRow {
6
+ scope: 'doc' | 'pv';
7
+ inputPath: string;
8
+ formFieldKey: string;
9
+ }
10
+ /**
11
+ * Serialize simple-table rows into a JSONata expression that maps `$form` onto
12
+ * a `{ doc, pv }` overlay. Dot-notation input paths expand into nested object
13
+ * literals (so `beslissing.tekst` becomes `{ "beslissing": { "tekst": ... } }`),
14
+ * preserving the legacy override semantics.
15
+ */
16
+ export declare function serializeOverrideRows(rows: OverrideRow[]): string;
17
+ /**
18
+ * Parse a JSONata override expression back into simple-table rows, or `null`
19
+ * when the expression is richer than the simple table can represent (anything
20
+ * beyond `doc`/`pv` objects whose leaves are plain `$form.<key>` references).
21
+ * A `null` result is the builder's signal to fall back to advanced mode.
22
+ */
23
+ export declare function parseOverrideJsonata(expression: string): OverrideRow[] | null;
24
+ /** Whether the expression can be edited in the simple table (round-trippable). */
25
+ export declare function isRoundTrippable(expression: string): boolean;
@@ -33,6 +33,12 @@ export interface PendingJob {
33
33
  tenantId: string;
34
34
  requestId: string;
35
35
  configurationTitle: string;
36
+ /**
37
+ * 'WAITING' — has the epistolaWaitFor token; the collector can correlate it.
38
+ * 'UNWIRED' — has the subscription but no token, so it can never be correlated (stuck); requestId is
39
+ * absent and reconcile cannot recover it. Surfaced so operators can see and fix the process model.
40
+ */
41
+ status: 'WAITING' | 'UNWIRED';
36
42
  }
37
43
  export interface PluginUsageEntry {
38
44
  processLinkId: string;
@@ -143,6 +149,19 @@ export interface FormCarrierIssue {
143
149
  missingComponents: number;
144
150
  readOnly: boolean;
145
151
  }
152
+ /**
153
+ * TEMPORARY. A form whose `epistola-document-preview` components still use the legacy
154
+ * override-mapping object format (`{ scope: { path: "form:key" } }`) instead of the new
155
+ * JSONata string over `$form`. Surfaced on the admin page so it can be re-saved in the
156
+ * form builder, which migrates it. `readOnly` flags classpath-deployed forms (migrate
157
+ * the source instead).
158
+ */
159
+ export interface LegacyOverrideForm {
160
+ formId: string;
161
+ name: string;
162
+ legacyComponents: number;
163
+ readOnly: boolean;
164
+ }
146
165
  /** TEMPORARY (removed in 1.0.0). Outcome of repairing one form's carrier. */
147
166
  export interface FormCarrierRepairResult {
148
167
  formId: string;
@@ -83,6 +83,15 @@ export interface VariableSuggestions {
83
83
  doc: string[];
84
84
  pv: string[];
85
85
  }
86
+ /**
87
+ * Raw `dataMapping` JSONata of a generate-document process link, keyed server-side by
88
+ * `(processDefinitionKey, activityId)`. Empty when the link or its mapping can't be resolved.
89
+ * The override builder statically extracts the referenced `$doc`/`$pv` paths from it to show
90
+ * the author which inputs this template's mapping consumes.
91
+ */
92
+ export interface ProcessLinkMapping {
93
+ dataMapping: string;
94
+ }
86
95
  export interface EvaluationResult {
87
96
  success: boolean;
88
97
  result: Record<string, any> | null;
@@ -1,7 +1,7 @@
1
1
  import { HttpClient } from '@angular/common/http';
2
2
  import { ConfigService } from '@valtimo/shared';
3
3
  import { Observable } from 'rxjs';
4
- import { BpmnValidationReport, CatalogRedeployResult, ChangelogRelease, ClasspathCatalog, ConnectionStatus, FormCarrierIssue, FormCarrierRepairResult, FormCarrierRepairSummary, PendingJob, PluginUsageEntry, ReconcileResult, VersionInfo } from '../models';
4
+ import { BpmnValidationReport, CatalogRedeployResult, ChangelogRelease, ClasspathCatalog, ConnectionStatus, FormCarrierIssue, FormCarrierRepairResult, FormCarrierRepairSummary, LegacyOverrideForm, PendingJob, PluginUsageEntry, ReconcileResult, VersionInfo } from '../models';
5
5
  import * as i0 from "@angular/core";
6
6
  /**
7
7
  * Service for Epistola plugin administrative operations.
@@ -70,6 +70,8 @@ export declare class EpistolaAdminService {
70
70
  repairFormCarrier(formId: string): Observable<FormCarrierRepairResult>;
71
71
  /** Repair every flagged form. */
72
72
  repairAllFormCarriers(): Observable<FormCarrierRepairSummary>;
73
+ /** Forms whose preview components still use the legacy override-mapping object format. */
74
+ getLegacyOverrideForms(): Observable<LegacyOverrideForm[]>;
73
75
  static ɵfac: i0.ɵɵFactoryDeclaration<EpistolaAdminService, never>;
74
76
  static ɵprov: i0.ɵɵInjectableDeclaration<EpistolaAdminService>;
75
77
  }
@@ -1,7 +1,7 @@
1
1
  import { HttpClient } from '@angular/common/http';
2
2
  import { ConfigService } from '@valtimo/shared';
3
3
  import { Observable } from 'rxjs';
4
- import { AttributeDefinition, CatalogInfo, EnvironmentInfo, ExpressionFunctionInfo, JsonataValidationResult, TemplateDetails, TemplateInfo, EvaluationResult, ValidateJsonataRequest, VariableSuggestions, VariantInfo } from '../models';
4
+ import { AttributeDefinition, CatalogInfo, EnvironmentInfo, ExpressionFunctionInfo, JsonataValidationResult, ProcessLinkMapping, TemplateDetails, TemplateInfo, EvaluationResult, ValidateJsonataRequest, VariableSuggestions, VariantInfo } from '../models';
5
5
  import * as i0 from "@angular/core";
6
6
  /**
7
7
  * Body of a {@link EpistolaPluginService.previewToBlob} call. Mirrors the
@@ -68,6 +68,12 @@ export declare class EpistolaPluginService {
68
68
  * Discover process variable names for a given process definition.
69
69
  */
70
70
  getProcessVariables(processDefinitionKey: string): Observable<string[]>;
71
+ /**
72
+ * Get the raw `dataMapping` JSONata of a generate-document process link, identified by its
73
+ * process definition key and activity id. The override builder extracts the referenced
74
+ * `$doc`/`$pv` paths from it to guide the author. Returns an empty mapping when unresolved.
75
+ */
76
+ getProcessLinkMapping(processDefinitionKey: string, activityId: string): Observable<ProcessLinkMapping>;
71
77
  /**
72
78
  * Get variable suggestions for JSONata autocompletion.
73
79
  */
@@ -0,0 +1,19 @@
1
+ /** A `$doc`/`$pv`/`$case` path referenced by a JSONata expression. */
2
+ export interface ReferencedPath {
3
+ scope: 'doc' | 'pv' | 'case';
4
+ /** Dotted path under the scope, e.g. `aanvrager.naam`. Empty for a whole-scope reference. */
5
+ path: string;
6
+ }
7
+ /**
8
+ * Statically extract every `$doc`/`$pv`/`$case` path referenced anywhere in a JSONata
9
+ * expression. Used to surface — informationally — which inputs a template's data mapping
10
+ * consumes, so the override-builder author sees what is worth overriding during preview.
11
+ *
12
+ * This is a best-effort static read: paths built dynamically (`$lookup`, custom functions,
13
+ * computed keys) can't be resolved and simply won't appear. Treat the result as suggestions,
14
+ * never as validation — an empty result (e.g. on a parse error) means "nothing to suggest".
15
+ *
16
+ * Generalizes the variable-path primitive in `utils/jsonata-converter.ts` (`classifyValue`)
17
+ * to recurse over the whole AST rather than only top-level object values.
18
+ */
19
+ export declare function extractReferencedPaths(expression: string | null | undefined): ReferencedPath[];
@@ -1,10 +1,10 @@
1
- import { ExpressionFunctionInfo, VariableSuggestions } from '../models';
1
+ import { ExpressionFunctionInfo } from '../models';
2
2
  /**
3
3
  * Shared state for the JSONata completion provider.
4
4
  * Updated by the editor component when suggestions/functions change.
5
5
  */
6
6
  export declare const jsonataCompletionData: {
7
- suggestions: VariableSuggestions | null;
7
+ variables: Record<string, string[]>;
8
8
  functions: ExpressionFunctionInfo[];
9
9
  };
10
10
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epistola.app/valtimo-plugin",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Epistola document generation plugin for Valtimo",
5
5
  "license": "EUPL-1.2",
6
6
  "repository": {
@@ -28,6 +28,7 @@
28
28
  "@angular/core": ">=17.0.0",
29
29
  "@angular/forms": ">=17.0.0",
30
30
  "@angular/router": ">=17.0.0",
31
+ "@formio/angular": "^7.0.0",
31
32
  "@valtimo/components": "^13.21.0",
32
33
  "@valtimo/plugin": "^13.21.0",
33
34
  "@valtimo/process-link": "^13.21.0",