@yourself.create/ngx-form-designer 0.0.3 → 0.0.4
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/uch-web-ngx-form-designer.mjs +2866 -408
- package/fesm2022/uch-web-ngx-form-designer.mjs.map +1 -1
- package/lib/ai/provide-form-designer-angai-feature.d.ts +16 -0
- package/lib/form-core/form-engine.d.ts +7 -3
- package/lib/form-core/form-event-runner.d.ts +14 -0
- package/lib/form-core/form-journey.models.d.ts +30 -0
- package/lib/form-core/models.d.ts +7 -1
- package/lib/form-designer/designer-state.service.d.ts +1 -1
- package/lib/form-designer/events-workspace.component.d.ts +28 -3
- package/lib/form-designer/form-designer-shell.component.d.ts +30 -5
- package/lib/form-designer/form-journey-state.service.d.ts +28 -0
- package/lib/form-designer/form-preview.component.d.ts +21 -2
- package/lib/form-designer/inspector-sections/inspector-backgrounds-section.component.d.ts +5 -0
- package/lib/form-designer/inspector-sections/inspector-typography-section.component.d.ts +1 -0
- package/lib/form-designer/json-form-designer.component.d.ts +21 -2
- package/lib/form-designer/layout-canvas.component.d.ts +3 -1
- package/lib/form-designer/template-library.d.ts +2 -0
- package/lib/form-renderer/form-journey-viewer.component.d.ts +51 -0
- package/lib/form-renderer/form-viewer/form-viewer.component.d.ts +16 -3
- package/lib/form-renderer/json-form-renderer.component.d.ts +10 -2
- package/lib/form-renderer/layout-node.component.d.ts +2 -1
- package/lib/ui/ui-color-swatch.component.d.ts +1 -0
- package/lib/website/website-preview-shell.component.d.ts +1 -1
- package/lib/widgets/field-widgets/checkbox-group/checkbox-group-widget.component.d.ts +5 -0
- package/lib/widgets/field-widgets/option-field-labels.d.ts +3 -0
- package/lib/widgets/field-widgets/radio/radio-widget.component.d.ts +5 -0
- package/lib/widgets/field-widgets/search/search-widget.component.d.ts +4 -0
- package/lib/widgets/field-widgets/select/select-widget.component.d.ts +9 -0
- package/lib/widgets/field-widgets/text-field/text-field.component.d.ts +3 -0
- package/package.json +3 -2
- package/public-api.d.ts +4 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { v4 } from 'uuid';
|
|
1
2
|
import * as i0 from '@angular/core';
|
|
2
3
|
import { Injectable, InjectionToken, NgModule, inject, signal, computed, EventEmitter, DestroyRef, Injector, afterNextRender, ViewContainerRef, Input, ViewChild, Output, Inject, ChangeDetectionStrategy, Component, effect, ElementRef, NgZone, input, output, HostListener, ContentChildren, untracked, ChangeDetectorRef, Pipe } from '@angular/core';
|
|
3
4
|
import { BehaviorSubject, Subject, merge, of, filter, map, debounceTime as debounceTime$1, skip, firstValueFrom } from 'rxjs';
|
|
4
|
-
import { v4 } from 'uuid';
|
|
5
5
|
import * as i1 from '@angular/common';
|
|
6
6
|
import { CommonModule, DOCUMENT } from '@angular/common';
|
|
7
7
|
import * as i2 from '@angular/forms';
|
|
@@ -14,7 +14,8 @@ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
|
14
14
|
import * as i5 from 'angular-resizable-element';
|
|
15
15
|
import { ResizableModule } from 'angular-resizable-element';
|
|
16
16
|
import loader from '@monaco-editor/loader';
|
|
17
|
-
import {
|
|
17
|
+
import { ColorPickerDirective } from 'ngx-color-picker';
|
|
18
|
+
import { defineAiTool, provideAngaiFeature, AI_BACKEND_CLIENT, AiChatDrawerComponent, AiWorkspaceComponent } from '@uch-web/angai';
|
|
18
19
|
import { Router, NavigationEnd } from '@angular/router';
|
|
19
20
|
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
|
20
21
|
import { NgSelectComponent } from '@ng-select/ng-select';
|
|
@@ -24,6 +25,243 @@ import { HttpClient, provideHttpClient } from '@angular/common/http';
|
|
|
24
25
|
|
|
25
26
|
const CURRENT_SCHEMA_VERSION = '1.0.0';
|
|
26
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Automatically computes and sets `hierarchyAccess` flags
|
|
30
|
+
* on each field's dataConfig based on dependency relationships.
|
|
31
|
+
*
|
|
32
|
+
* Logic:
|
|
33
|
+
* - hierarchyAccess = true if field has dependsOn OR other fields depend on it
|
|
34
|
+
*/
|
|
35
|
+
function computeAccessFlags(schema) {
|
|
36
|
+
if (!schema.fields || schema.fields.length === 0) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const fieldByIdOrName = new Map();
|
|
40
|
+
for (const field of schema.fields) {
|
|
41
|
+
fieldByIdOrName.set(field.id, field);
|
|
42
|
+
if (field.name) {
|
|
43
|
+
fieldByIdOrName.set(field.name, field);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Build a map of canonical field ids that are depended upon
|
|
47
|
+
const dependedUponFieldIds = new Set();
|
|
48
|
+
for (const field of schema.fields) {
|
|
49
|
+
if (field.dataConfig?.dependsOn && field.dataConfig.dependsOn.length > 0) {
|
|
50
|
+
for (const dep of field.dataConfig.dependsOn) {
|
|
51
|
+
const dependedField = fieldByIdOrName.get(dep.fieldId);
|
|
52
|
+
if (dependedField) {
|
|
53
|
+
dependedUponFieldIds.add(dependedField.id);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Compute flags for each field
|
|
59
|
+
for (const field of schema.fields) {
|
|
60
|
+
const hasDependsOn = !!field.dataConfig?.dependsOn?.length;
|
|
61
|
+
const isDependedUpon = dependedUponFieldIds.has(field.id);
|
|
62
|
+
const hierarchyAccess = hasDependsOn || isDependedUpon;
|
|
63
|
+
if (!field.dataConfig) {
|
|
64
|
+
if (!hierarchyAccess) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Persist hierarchy participation for fields that act as dependency parents
|
|
68
|
+
// even when they did not have a dataConfig previously.
|
|
69
|
+
field.dataConfig = {
|
|
70
|
+
type: 'static',
|
|
71
|
+
hierarchyAccess
|
|
72
|
+
};
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
// hierarchyAccess: true if field participates in hierarchy (either direction)
|
|
76
|
+
field.dataConfig.hierarchyAccess = hierarchyAccess;
|
|
77
|
+
}
|
|
78
|
+
for (const field of schema.fields) {
|
|
79
|
+
const itemSchema = field.repeatable?.itemSchema;
|
|
80
|
+
if (!itemSchema)
|
|
81
|
+
continue;
|
|
82
|
+
computeAccessFlags(itemSchema);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Metadata field is intended for AI/LLM and project-level information (prompts, generation parameters, tags).
|
|
88
|
+
* SchemaVersion will be used for future migrations as more flavors (audio/video/image editors, tables, etc.) are added.
|
|
89
|
+
*/
|
|
90
|
+
function createEmptySchema(flavor = 'form', opts) {
|
|
91
|
+
return {
|
|
92
|
+
id: opts?.id || v4(),
|
|
93
|
+
version: '1.0',
|
|
94
|
+
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
95
|
+
flavor,
|
|
96
|
+
title: opts?.title || 'New Form',
|
|
97
|
+
metadata: {},
|
|
98
|
+
fields: [],
|
|
99
|
+
layout: {
|
|
100
|
+
id: v4(),
|
|
101
|
+
type: 'col', // Root is a vertical Page/Column
|
|
102
|
+
responsive: { xs: 12 },
|
|
103
|
+
children: [
|
|
104
|
+
{
|
|
105
|
+
id: v4(),
|
|
106
|
+
type: 'row', // Initial Row
|
|
107
|
+
children: [
|
|
108
|
+
{
|
|
109
|
+
id: v4(),
|
|
110
|
+
type: 'col',
|
|
111
|
+
responsive: { xs: 12 },
|
|
112
|
+
children: []
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function serializeSchema(schema) {
|
|
121
|
+
const schemaForSerialization = JSON.parse(JSON.stringify(schema));
|
|
122
|
+
computeAccessFlags(schemaForSerialization);
|
|
123
|
+
return JSON.stringify(schemaForSerialization, null, 2);
|
|
124
|
+
}
|
|
125
|
+
function parseSchema(json) {
|
|
126
|
+
let schema;
|
|
127
|
+
try {
|
|
128
|
+
schema = JSON.parse(json);
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
throw new Error('Invalid JSON');
|
|
132
|
+
}
|
|
133
|
+
if (!schema.id || !schema.layout) {
|
|
134
|
+
throw new Error('Invalid Schema Structure');
|
|
135
|
+
}
|
|
136
|
+
// Normalization / Migration Logic
|
|
137
|
+
if (!schema.schemaVersion) {
|
|
138
|
+
schema.schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
139
|
+
}
|
|
140
|
+
// Default flavor if missing (legacy support)
|
|
141
|
+
if (!schema.flavor) {
|
|
142
|
+
schema.flavor = 'form';
|
|
143
|
+
}
|
|
144
|
+
// TODO: Future migrations based on schemaVersion can go here.
|
|
145
|
+
// Auto-compute access flags based on dependencies
|
|
146
|
+
computeAccessFlags(schema);
|
|
147
|
+
return schema;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function normalizePageName(name, schema) {
|
|
151
|
+
const explicitName = (name ?? '').trim();
|
|
152
|
+
if (explicitName)
|
|
153
|
+
return explicitName;
|
|
154
|
+
const schemaTitle = (schema.title ?? '').trim();
|
|
155
|
+
if (schemaTitle)
|
|
156
|
+
return schemaTitle;
|
|
157
|
+
return 'Page';
|
|
158
|
+
}
|
|
159
|
+
function toRouteSegment(input) {
|
|
160
|
+
return input
|
|
161
|
+
.trim()
|
|
162
|
+
.toLowerCase()
|
|
163
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
164
|
+
.replace(/^-+|-+$/g, '');
|
|
165
|
+
}
|
|
166
|
+
function normalizeRoute(route, name) {
|
|
167
|
+
const raw = (route ?? '').trim().toLowerCase();
|
|
168
|
+
if (!raw) {
|
|
169
|
+
const segment = toRouteSegment(name);
|
|
170
|
+
return segment ? `/${segment}` : '/step';
|
|
171
|
+
}
|
|
172
|
+
return raw.startsWith('/') ? raw : `/${raw}`;
|
|
173
|
+
}
|
|
174
|
+
function normalizePage(page) {
|
|
175
|
+
const schema = page.schema;
|
|
176
|
+
const name = normalizePageName(page.name, schema);
|
|
177
|
+
return {
|
|
178
|
+
id: page.id || v4(),
|
|
179
|
+
name,
|
|
180
|
+
route: normalizeRoute(page.route, name),
|
|
181
|
+
schema: {
|
|
182
|
+
...schema,
|
|
183
|
+
title: schema.title ?? name
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function createFormJourneyPage(opts) {
|
|
188
|
+
const schema = opts?.schema ?? createEmptySchema('form');
|
|
189
|
+
const name = normalizePageName(opts?.name, schema);
|
|
190
|
+
return {
|
|
191
|
+
id: opts?.id ?? v4(),
|
|
192
|
+
name,
|
|
193
|
+
route: normalizeRoute(opts?.route, name),
|
|
194
|
+
schema: {
|
|
195
|
+
...schema,
|
|
196
|
+
title: schema.title ?? name
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function createFormJourneyProject(opts) {
|
|
201
|
+
const pages = (opts?.pages?.length ? opts.pages : [
|
|
202
|
+
createFormJourneyPage({
|
|
203
|
+
name: 'Step 1',
|
|
204
|
+
schema: createEmptySchema('form', { title: 'Step 1' })
|
|
205
|
+
})
|
|
206
|
+
]).map(normalizePage);
|
|
207
|
+
const startPageId = pages.some(page => page.id === opts?.startPageId)
|
|
208
|
+
? opts?.startPageId
|
|
209
|
+
: pages[0].id;
|
|
210
|
+
return {
|
|
211
|
+
id: opts?.id ?? v4(),
|
|
212
|
+
title: opts?.title ?? pages[0]?.schema.title ?? 'New Journey',
|
|
213
|
+
pages,
|
|
214
|
+
startPageId,
|
|
215
|
+
metadata: opts?.metadata ?? {}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function isFormJourneyProject(value) {
|
|
219
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
220
|
+
return false;
|
|
221
|
+
const candidate = value;
|
|
222
|
+
if (!Array.isArray(candidate.pages))
|
|
223
|
+
return false;
|
|
224
|
+
if (typeof candidate.startPageId !== 'string' || candidate.startPageId.trim().length === 0)
|
|
225
|
+
return false;
|
|
226
|
+
return candidate.pages.every(page => {
|
|
227
|
+
if (!page || typeof page !== 'object')
|
|
228
|
+
return false;
|
|
229
|
+
const p = page;
|
|
230
|
+
if (typeof p.id !== 'string' || typeof p.name !== 'string')
|
|
231
|
+
return false;
|
|
232
|
+
if (!p.schema || typeof p.schema !== 'object' || Array.isArray(p.schema))
|
|
233
|
+
return false;
|
|
234
|
+
return 'layout' in p.schema && 'fields' in p.schema;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
function normalizeToJourney(value) {
|
|
238
|
+
if (isFormJourneyProject(value)) {
|
|
239
|
+
return createFormJourneyProject({
|
|
240
|
+
id: value.id,
|
|
241
|
+
title: value.title,
|
|
242
|
+
pages: value.pages.map(page => normalizePage(page)),
|
|
243
|
+
startPageId: value.startPageId,
|
|
244
|
+
metadata: value.metadata
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
const singlePage = createFormJourneyPage({
|
|
248
|
+
name: value.title ?? 'Step 1',
|
|
249
|
+
schema: value
|
|
250
|
+
});
|
|
251
|
+
return createFormJourneyProject({
|
|
252
|
+
title: value.title ?? 'New Journey',
|
|
253
|
+
pages: [singlePage],
|
|
254
|
+
startPageId: singlePage.id,
|
|
255
|
+
metadata: value.metadata
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
function unwrapSinglePageJourney(value) {
|
|
259
|
+
if (value.pages.length === 1) {
|
|
260
|
+
return value.pages[0].schema;
|
|
261
|
+
}
|
|
262
|
+
return value;
|
|
263
|
+
}
|
|
264
|
+
|
|
27
265
|
class RuleEvaluationService {
|
|
28
266
|
constructor() { }
|
|
29
267
|
/**
|
|
@@ -145,6 +383,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
145
383
|
class FormEngine {
|
|
146
384
|
schema;
|
|
147
385
|
values = {};
|
|
386
|
+
fieldLabels = {};
|
|
148
387
|
errors = {};
|
|
149
388
|
ruleEvaluator = new RuleEvaluationService();
|
|
150
389
|
// Reactive Streams
|
|
@@ -163,9 +402,10 @@ class FormEngine {
|
|
|
163
402
|
valueChanges: this.valueChanges$
|
|
164
403
|
};
|
|
165
404
|
}
|
|
166
|
-
constructor(schema, initialValues = {}) {
|
|
405
|
+
constructor(schema, initialValues = {}, initialFieldLabels = {}) {
|
|
167
406
|
this.schema = schema;
|
|
168
407
|
this.values = { ...initialValues };
|
|
408
|
+
this.fieldLabels = { ...initialFieldLabels };
|
|
169
409
|
// Initialize default values if missing
|
|
170
410
|
this.schema.fields.forEach(field => {
|
|
171
411
|
if (this.values[field.name] === undefined) {
|
|
@@ -212,6 +452,19 @@ class FormEngine {
|
|
|
212
452
|
getValues() {
|
|
213
453
|
return { ...this.values };
|
|
214
454
|
}
|
|
455
|
+
getFieldLabel(fieldName) {
|
|
456
|
+
return this.fieldLabels[fieldName];
|
|
457
|
+
}
|
|
458
|
+
getFieldLabels() {
|
|
459
|
+
return { ...this.fieldLabels };
|
|
460
|
+
}
|
|
461
|
+
setFieldLabel(fieldName, label) {
|
|
462
|
+
if (label === undefined) {
|
|
463
|
+
delete this.fieldLabels[fieldName];
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
this.fieldLabels[fieldName] = Array.isArray(label) ? [...label] : label;
|
|
467
|
+
}
|
|
215
468
|
getErrors() {
|
|
216
469
|
return { ...this.errors };
|
|
217
470
|
}
|
|
@@ -411,130 +664,8 @@ class FormEngine {
|
|
|
411
664
|
return currentState;
|
|
412
665
|
}
|
|
413
666
|
}
|
|
414
|
-
function createFormEngine(schema, initialValues = {}) {
|
|
415
|
-
return new FormEngine(schema, initialValues);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Automatically computes and sets `hierarchyAccess` flags
|
|
420
|
-
* on each field's dataConfig based on dependency relationships.
|
|
421
|
-
*
|
|
422
|
-
* Logic:
|
|
423
|
-
* - hierarchyAccess = true if field has dependsOn OR other fields depend on it
|
|
424
|
-
*/
|
|
425
|
-
function computeAccessFlags(schema) {
|
|
426
|
-
if (!schema.fields || schema.fields.length === 0) {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
const fieldByIdOrName = new Map();
|
|
430
|
-
for (const field of schema.fields) {
|
|
431
|
-
fieldByIdOrName.set(field.id, field);
|
|
432
|
-
if (field.name) {
|
|
433
|
-
fieldByIdOrName.set(field.name, field);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
// Build a map of canonical field ids that are depended upon
|
|
437
|
-
const dependedUponFieldIds = new Set();
|
|
438
|
-
for (const field of schema.fields) {
|
|
439
|
-
if (field.dataConfig?.dependsOn && field.dataConfig.dependsOn.length > 0) {
|
|
440
|
-
for (const dep of field.dataConfig.dependsOn) {
|
|
441
|
-
const dependedField = fieldByIdOrName.get(dep.fieldId);
|
|
442
|
-
if (dependedField) {
|
|
443
|
-
dependedUponFieldIds.add(dependedField.id);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
// Compute flags for each field
|
|
449
|
-
for (const field of schema.fields) {
|
|
450
|
-
const hasDependsOn = !!field.dataConfig?.dependsOn?.length;
|
|
451
|
-
const isDependedUpon = dependedUponFieldIds.has(field.id);
|
|
452
|
-
const hierarchyAccess = hasDependsOn || isDependedUpon;
|
|
453
|
-
if (!field.dataConfig) {
|
|
454
|
-
if (!hierarchyAccess) {
|
|
455
|
-
continue;
|
|
456
|
-
}
|
|
457
|
-
// Persist hierarchy participation for fields that act as dependency parents
|
|
458
|
-
// even when they did not have a dataConfig previously.
|
|
459
|
-
field.dataConfig = {
|
|
460
|
-
type: 'static',
|
|
461
|
-
hierarchyAccess
|
|
462
|
-
};
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
// hierarchyAccess: true if field participates in hierarchy (either direction)
|
|
466
|
-
field.dataConfig.hierarchyAccess = hierarchyAccess;
|
|
467
|
-
}
|
|
468
|
-
for (const field of schema.fields) {
|
|
469
|
-
const itemSchema = field.repeatable?.itemSchema;
|
|
470
|
-
if (!itemSchema)
|
|
471
|
-
continue;
|
|
472
|
-
computeAccessFlags(itemSchema);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* Metadata field is intended for AI/LLM and project-level information (prompts, generation parameters, tags).
|
|
478
|
-
* SchemaVersion will be used for future migrations as more flavors (audio/video/image editors, tables, etc.) are added.
|
|
479
|
-
*/
|
|
480
|
-
function createEmptySchema(flavor = 'form', opts) {
|
|
481
|
-
return {
|
|
482
|
-
id: opts?.id || v4(),
|
|
483
|
-
version: '1.0',
|
|
484
|
-
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
485
|
-
flavor,
|
|
486
|
-
title: opts?.title || 'New Form',
|
|
487
|
-
metadata: {},
|
|
488
|
-
fields: [],
|
|
489
|
-
layout: {
|
|
490
|
-
id: v4(),
|
|
491
|
-
type: 'col', // Root is a vertical Page/Column
|
|
492
|
-
responsive: { xs: 12 },
|
|
493
|
-
children: [
|
|
494
|
-
{
|
|
495
|
-
id: v4(),
|
|
496
|
-
type: 'row', // Initial Row
|
|
497
|
-
children: [
|
|
498
|
-
{
|
|
499
|
-
id: v4(),
|
|
500
|
-
type: 'col',
|
|
501
|
-
responsive: { xs: 12 },
|
|
502
|
-
children: []
|
|
503
|
-
}
|
|
504
|
-
]
|
|
505
|
-
}
|
|
506
|
-
]
|
|
507
|
-
}
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
function serializeSchema(schema) {
|
|
511
|
-
const schemaForSerialization = JSON.parse(JSON.stringify(schema));
|
|
512
|
-
computeAccessFlags(schemaForSerialization);
|
|
513
|
-
return JSON.stringify(schemaForSerialization, null, 2);
|
|
514
|
-
}
|
|
515
|
-
function parseSchema(json) {
|
|
516
|
-
let schema;
|
|
517
|
-
try {
|
|
518
|
-
schema = JSON.parse(json);
|
|
519
|
-
}
|
|
520
|
-
catch (e) {
|
|
521
|
-
throw new Error('Invalid JSON');
|
|
522
|
-
}
|
|
523
|
-
if (!schema.id || !schema.layout) {
|
|
524
|
-
throw new Error('Invalid Schema Structure');
|
|
525
|
-
}
|
|
526
|
-
// Normalization / Migration Logic
|
|
527
|
-
if (!schema.schemaVersion) {
|
|
528
|
-
schema.schemaVersion = CURRENT_SCHEMA_VERSION;
|
|
529
|
-
}
|
|
530
|
-
// Default flavor if missing (legacy support)
|
|
531
|
-
if (!schema.flavor) {
|
|
532
|
-
schema.flavor = 'form';
|
|
533
|
-
}
|
|
534
|
-
// TODO: Future migrations based on schemaVersion can go here.
|
|
535
|
-
// Auto-compute access flags based on dependencies
|
|
536
|
-
computeAccessFlags(schema);
|
|
537
|
-
return schema;
|
|
667
|
+
function createFormEngine(schema, initialValues = {}, initialFieldLabels = {}) {
|
|
668
|
+
return new FormEngine(schema, initialValues, initialFieldLabels);
|
|
538
669
|
}
|
|
539
670
|
|
|
540
671
|
/**
|
|
@@ -2692,6 +2823,7 @@ class LayoutNodeComponent {
|
|
|
2692
2823
|
engine;
|
|
2693
2824
|
fields = [];
|
|
2694
2825
|
designMode = false;
|
|
2826
|
+
showLayoutGuides = true;
|
|
2695
2827
|
readOnlyMode = false;
|
|
2696
2828
|
scopePath = [];
|
|
2697
2829
|
device = 'desktop';
|
|
@@ -3154,7 +3286,9 @@ class LayoutNodeComponent {
|
|
|
3154
3286
|
getColContainerClasses(node) {
|
|
3155
3287
|
const widthClasses = this.getColClasses(node);
|
|
3156
3288
|
const interactionClasses = this.designMode
|
|
3157
|
-
?
|
|
3289
|
+
? this.showLayoutGuides
|
|
3290
|
+
? 'min-h-[50px] relative transition-all cursor-pointer border border-transparent hover:border-blue-200/50'
|
|
3291
|
+
: 'min-h-[50px] relative transition-all cursor-pointer'
|
|
3158
3292
|
: 'min-h-[50px] relative transition-all';
|
|
3159
3293
|
return `${interactionClasses} ${widthClasses}`.trim();
|
|
3160
3294
|
}
|
|
@@ -3294,7 +3428,7 @@ class LayoutNodeComponent {
|
|
|
3294
3428
|
return this.fields.find(field => field.id === widget.refId);
|
|
3295
3429
|
}
|
|
3296
3430
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutNodeComponent, deps: [{ token: WIDGET_DEFINITIONS }, { token: DesignerStateService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3297
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: LayoutNodeComponent, isStandalone: true, selector: "app-layout-node", inputs: { node: "node", engine: "engine", fields: "fields", designMode: "designMode", readOnlyMode: "readOnlyMode", scopePath: "scopePath", device: "device", breakpoint: "breakpoint", connectedDropLists: "connectedDropLists" }, outputs: { nodeDrop: "nodeDrop", nodeSelect: "nodeSelect" }, viewQueries: [{ propertyName: "widgetContainer", first: true, predicate: ["widgetContainer"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: `
|
|
3431
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: LayoutNodeComponent, isStandalone: true, selector: "app-layout-node", inputs: { node: "node", engine: "engine", fields: "fields", designMode: "designMode", showLayoutGuides: "showLayoutGuides", readOnlyMode: "readOnlyMode", scopePath: "scopePath", device: "device", breakpoint: "breakpoint", connectedDropLists: "connectedDropLists" }, outputs: { nodeDrop: "nodeDrop", nodeSelect: "nodeSelect" }, viewQueries: [{ propertyName: "widgetContainer", first: true, predicate: ["widgetContainer"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: `
|
|
3298
3432
|
<ng-container [ngSwitch]="node.type">
|
|
3299
3433
|
|
|
3300
3434
|
<!-- ROW -->
|
|
@@ -3308,9 +3442,9 @@ class LayoutNodeComponent {
|
|
|
3308
3442
|
(resizeEnd)="onHeightResizeEnd(node, $event)"
|
|
3309
3443
|
(click)="onRowClick($event)"
|
|
3310
3444
|
(contextmenu)="onRowContextMenu($event)"
|
|
3311
|
-
[class.outline-dashed]="designMode"
|
|
3312
|
-
[class.outline-1]="designMode"
|
|
3313
|
-
[class.outline-blue-200]="designMode && !isSelected"
|
|
3445
|
+
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3446
|
+
[class.outline-1]="designMode && showLayoutGuides"
|
|
3447
|
+
[class.outline-blue-200]="designMode && showLayoutGuides && !isSelected"
|
|
3314
3448
|
[class.ring-2]="designMode && isSelected"
|
|
3315
3449
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3316
3450
|
[class.bg-blue-50]="designMode && isSelected">
|
|
@@ -3337,7 +3471,7 @@ class LayoutNodeComponent {
|
|
|
3337
3471
|
</div>
|
|
3338
3472
|
|
|
3339
3473
|
<!-- Visual Label for Row when hovered (not selected) -->
|
|
3340
|
-
<div *ngIf="designMode && !isSelected" class="absolute -top-3 left-0 bg-blue-500 text-white text-[10px] px-1 rounded rounded-b-none opacity-0 group-hover:opacity-100 transition-opacity z-10">
|
|
3474
|
+
<div *ngIf="designMode && showLayoutGuides && !isSelected" class="absolute -top-3 left-0 bg-blue-500 text-white text-[10px] px-1 rounded rounded-b-none opacity-0 group-hover:opacity-100 transition-opacity z-10">
|
|
3341
3475
|
ROW
|
|
3342
3476
|
</div>
|
|
3343
3477
|
|
|
@@ -3346,6 +3480,7 @@ class LayoutNodeComponent {
|
|
|
3346
3480
|
[engine]="engine"
|
|
3347
3481
|
[fields]="fields"
|
|
3348
3482
|
[designMode]="designMode"
|
|
3483
|
+
[showLayoutGuides]="showLayoutGuides"
|
|
3349
3484
|
[readOnlyMode]="readOnlyMode"
|
|
3350
3485
|
[scopePath]="scopePath"
|
|
3351
3486
|
[device]="device"
|
|
@@ -3382,9 +3517,9 @@ class LayoutNodeComponent {
|
|
|
3382
3517
|
[id]="getScopedNodeId(node.id)"
|
|
3383
3518
|
[cdkDropListConnectedTo]="connectedDropLists"
|
|
3384
3519
|
(cdkDropListDropped)="onDrop($event)"
|
|
3385
|
-
[class.outline-dashed]="designMode"
|
|
3386
|
-
[class.outline-1]="designMode"
|
|
3387
|
-
[class.outline-gray-300]="designMode && !isSelected"
|
|
3520
|
+
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3521
|
+
[class.outline-1]="designMode && showLayoutGuides"
|
|
3522
|
+
[class.outline-gray-300]="designMode && showLayoutGuides && !isSelected"
|
|
3388
3523
|
[class.ring-2]="designMode && isSelected"
|
|
3389
3524
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3390
3525
|
[class.bg-blue-50]="designMode && isSelected && asCol(node).children.length === 0">
|
|
@@ -3433,6 +3568,7 @@ class LayoutNodeComponent {
|
|
|
3433
3568
|
[engine]="engine"
|
|
3434
3569
|
[fields]="fields"
|
|
3435
3570
|
[designMode]="designMode"
|
|
3571
|
+
[showLayoutGuides]="showLayoutGuides"
|
|
3436
3572
|
[readOnlyMode]="readOnlyMode"
|
|
3437
3573
|
[scopePath]="scopePath"
|
|
3438
3574
|
[device]="device"
|
|
@@ -3537,7 +3673,7 @@ class LayoutNodeComponent {
|
|
|
3537
3673
|
</ng-container>
|
|
3538
3674
|
|
|
3539
3675
|
</ng-container>
|
|
3540
|
-
`, isInline: true, dependencies: [{ kind: "component", type: LayoutNodeComponent, selector: "app-layout-node", inputs: ["node", "engine", "fields", "designMode", "readOnlyMode", "scopePath", "device", "breakpoint", "connectedDropLists"], outputs: ["nodeDrop", "nodeSelect"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i3.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: ResizableModule }, { kind: "directive", type: i5.ResizableDirective, selector: "[mwlResizable]", inputs: ["validateResize", "enableGhostResize", "resizeSnapGrid", "resizeCursors", "ghostElementPositioning", "allowNegativeResizes", "mouseMoveThrottleMS"], outputs: ["resizeStart", "resizing", "resizeEnd"], exportAs: ["mwlResizable"] }, { kind: "directive", type: i5.ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: ["resizeEdges", "resizableContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3676
|
+
`, isInline: true, dependencies: [{ kind: "component", type: LayoutNodeComponent, selector: "app-layout-node", inputs: ["node", "engine", "fields", "designMode", "showLayoutGuides", "readOnlyMode", "scopePath", "device", "breakpoint", "connectedDropLists"], outputs: ["nodeDrop", "nodeSelect"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i3.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i3.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i3.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: ResizableModule }, { kind: "directive", type: i5.ResizableDirective, selector: "[mwlResizable]", inputs: ["validateResize", "enableGhostResize", "resizeSnapGrid", "resizeCursors", "ghostElementPositioning", "allowNegativeResizes", "mouseMoveThrottleMS"], outputs: ["resizeStart", "resizing", "resizeEnd"], exportAs: ["mwlResizable"] }, { kind: "directive", type: i5.ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: ["resizeEdges", "resizableContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3541
3677
|
}
|
|
3542
3678
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutNodeComponent, decorators: [{
|
|
3543
3679
|
type: Component,
|
|
@@ -3560,9 +3696,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3560
3696
|
(resizeEnd)="onHeightResizeEnd(node, $event)"
|
|
3561
3697
|
(click)="onRowClick($event)"
|
|
3562
3698
|
(contextmenu)="onRowContextMenu($event)"
|
|
3563
|
-
[class.outline-dashed]="designMode"
|
|
3564
|
-
[class.outline-1]="designMode"
|
|
3565
|
-
[class.outline-blue-200]="designMode && !isSelected"
|
|
3699
|
+
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3700
|
+
[class.outline-1]="designMode && showLayoutGuides"
|
|
3701
|
+
[class.outline-blue-200]="designMode && showLayoutGuides && !isSelected"
|
|
3566
3702
|
[class.ring-2]="designMode && isSelected"
|
|
3567
3703
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3568
3704
|
[class.bg-blue-50]="designMode && isSelected">
|
|
@@ -3589,7 +3725,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3589
3725
|
</div>
|
|
3590
3726
|
|
|
3591
3727
|
<!-- Visual Label for Row when hovered (not selected) -->
|
|
3592
|
-
<div *ngIf="designMode && !isSelected" class="absolute -top-3 left-0 bg-blue-500 text-white text-[10px] px-1 rounded rounded-b-none opacity-0 group-hover:opacity-100 transition-opacity z-10">
|
|
3728
|
+
<div *ngIf="designMode && showLayoutGuides && !isSelected" class="absolute -top-3 left-0 bg-blue-500 text-white text-[10px] px-1 rounded rounded-b-none opacity-0 group-hover:opacity-100 transition-opacity z-10">
|
|
3593
3729
|
ROW
|
|
3594
3730
|
</div>
|
|
3595
3731
|
|
|
@@ -3598,6 +3734,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3598
3734
|
[engine]="engine"
|
|
3599
3735
|
[fields]="fields"
|
|
3600
3736
|
[designMode]="designMode"
|
|
3737
|
+
[showLayoutGuides]="showLayoutGuides"
|
|
3601
3738
|
[readOnlyMode]="readOnlyMode"
|
|
3602
3739
|
[scopePath]="scopePath"
|
|
3603
3740
|
[device]="device"
|
|
@@ -3634,9 +3771,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3634
3771
|
[id]="getScopedNodeId(node.id)"
|
|
3635
3772
|
[cdkDropListConnectedTo]="connectedDropLists"
|
|
3636
3773
|
(cdkDropListDropped)="onDrop($event)"
|
|
3637
|
-
[class.outline-dashed]="designMode"
|
|
3638
|
-
[class.outline-1]="designMode"
|
|
3639
|
-
[class.outline-gray-300]="designMode && !isSelected"
|
|
3774
|
+
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3775
|
+
[class.outline-1]="designMode && showLayoutGuides"
|
|
3776
|
+
[class.outline-gray-300]="designMode && showLayoutGuides && !isSelected"
|
|
3640
3777
|
[class.ring-2]="designMode && isSelected"
|
|
3641
3778
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3642
3779
|
[class.bg-blue-50]="designMode && isSelected && asCol(node).children.length === 0">
|
|
@@ -3685,6 +3822,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3685
3822
|
[engine]="engine"
|
|
3686
3823
|
[fields]="fields"
|
|
3687
3824
|
[designMode]="designMode"
|
|
3825
|
+
[showLayoutGuides]="showLayoutGuides"
|
|
3688
3826
|
[readOnlyMode]="readOnlyMode"
|
|
3689
3827
|
[scopePath]="scopePath"
|
|
3690
3828
|
[device]="device"
|
|
@@ -3802,6 +3940,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3802
3940
|
type: Input
|
|
3803
3941
|
}], designMode: [{
|
|
3804
3942
|
type: Input
|
|
3943
|
+
}], showLayoutGuides: [{
|
|
3944
|
+
type: Input
|
|
3805
3945
|
}], readOnlyMode: [{
|
|
3806
3946
|
type: Input
|
|
3807
3947
|
}], scopePath: [{
|
|
@@ -3892,6 +4032,7 @@ class FormEventRunner {
|
|
|
3892
4032
|
logger;
|
|
3893
4033
|
apiExecutor;
|
|
3894
4034
|
dataSourceWriter;
|
|
4035
|
+
navigateToPage;
|
|
3895
4036
|
constructor(engine, loggerOrOptions = NOOP_LOGGER) {
|
|
3896
4037
|
this.engine = engine;
|
|
3897
4038
|
if (isEventLogger(loggerOrOptions)) {
|
|
@@ -3901,6 +4042,7 @@ class FormEventRunner {
|
|
|
3901
4042
|
this.logger = loggerOrOptions.logger ?? NOOP_LOGGER;
|
|
3902
4043
|
this.apiExecutor = loggerOrOptions.apiExecutor;
|
|
3903
4044
|
this.dataSourceWriter = loggerOrOptions.dataSourceWriter;
|
|
4045
|
+
this.navigateToPage = loggerOrOptions.navigateToPage;
|
|
3904
4046
|
}
|
|
3905
4047
|
this.sub = this.engine.events$.subscribe(evt => {
|
|
3906
4048
|
void this.handleEvent(evt);
|
|
@@ -3925,7 +4067,10 @@ class FormEventRunner {
|
|
|
3925
4067
|
const bindings = field.events.filter(b => b.on === evt.type && b.enabled !== false);
|
|
3926
4068
|
for (const binding of bindings) {
|
|
3927
4069
|
for (const action of binding.actions) {
|
|
3928
|
-
await this.executeAction(action, binding.id, evt, schema.fields);
|
|
4070
|
+
const stop = await this.executeAction(action, binding.id, evt, schema.fields);
|
|
4071
|
+
if (stop) {
|
|
4072
|
+
return;
|
|
4073
|
+
}
|
|
3929
4074
|
}
|
|
3930
4075
|
}
|
|
3931
4076
|
}
|
|
@@ -3936,13 +4081,17 @@ class FormEventRunner {
|
|
|
3936
4081
|
async executeAction(action, eventId, evt, fields) {
|
|
3937
4082
|
if (action.type === 'log') {
|
|
3938
4083
|
this.logger.log(action.message || 'Event fired', { event: evt });
|
|
3939
|
-
return;
|
|
4084
|
+
return false;
|
|
3940
4085
|
}
|
|
3941
4086
|
if (action.type === 'setValue') {
|
|
3942
4087
|
this.handleSetValue(action, evt, fields);
|
|
3943
|
-
return;
|
|
4088
|
+
return false;
|
|
4089
|
+
}
|
|
4090
|
+
if (action.type === 'navigate') {
|
|
4091
|
+
return this.handleNavigateAction(action, fields);
|
|
3944
4092
|
}
|
|
3945
4093
|
await this.handleApiAction(action, eventId, evt, fields);
|
|
4094
|
+
return false;
|
|
3946
4095
|
}
|
|
3947
4096
|
handleSetValue(action, evt, fields) {
|
|
3948
4097
|
const target = fields.find(f => f.id === action.targetFieldId);
|
|
@@ -4019,6 +4168,119 @@ class FormEventRunner {
|
|
|
4019
4168
|
});
|
|
4020
4169
|
}
|
|
4021
4170
|
}
|
|
4171
|
+
async handleNavigateAction(action, fields) {
|
|
4172
|
+
const targetPageId = action.targetPageId?.trim();
|
|
4173
|
+
if (!targetPageId) {
|
|
4174
|
+
this.logger.warn('Navigate action skipped because targetPageId is missing.', { action });
|
|
4175
|
+
return false;
|
|
4176
|
+
}
|
|
4177
|
+
if (!this.evaluateNavigateCondition(action.when, fields)) {
|
|
4178
|
+
return false;
|
|
4179
|
+
}
|
|
4180
|
+
if (!this.navigateToPage) {
|
|
4181
|
+
this.logger.warn('Navigate action skipped because no navigateToPage handler was provided.', { action });
|
|
4182
|
+
return false;
|
|
4183
|
+
}
|
|
4184
|
+
try {
|
|
4185
|
+
const result = await this.navigateToPage(targetPageId);
|
|
4186
|
+
if (!result?.ok) {
|
|
4187
|
+
this.logger.warn('Navigate action was blocked by navigateToPage handler.', { action, result });
|
|
4188
|
+
return false;
|
|
4189
|
+
}
|
|
4190
|
+
return true;
|
|
4191
|
+
}
|
|
4192
|
+
catch (error) {
|
|
4193
|
+
this.logger.warn('Navigate action execution failed.', { action, error });
|
|
4194
|
+
return false;
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
evaluateNavigateCondition(group, fields) {
|
|
4198
|
+
if (!group)
|
|
4199
|
+
return true;
|
|
4200
|
+
return this.evaluateLogicGroup(group, fields);
|
|
4201
|
+
}
|
|
4202
|
+
evaluateLogicGroup(group, fields) {
|
|
4203
|
+
const results = group.conditions.map(condition => this.isLogicCondition(condition)
|
|
4204
|
+
? this.evaluateLogicCondition(condition, fields)
|
|
4205
|
+
: this.evaluateLogicGroup(condition, fields));
|
|
4206
|
+
return group.operator === 'AND'
|
|
4207
|
+
? results.every(Boolean)
|
|
4208
|
+
: results.some(Boolean);
|
|
4209
|
+
}
|
|
4210
|
+
isLogicCondition(value) {
|
|
4211
|
+
return 'fieldId' in value;
|
|
4212
|
+
}
|
|
4213
|
+
evaluateLogicCondition(condition, fields) {
|
|
4214
|
+
const left = this.getFieldValue(condition.fieldId, fields);
|
|
4215
|
+
const right = condition.valueSource === 'field'
|
|
4216
|
+
? this.getFieldValue(condition.valueFieldId ?? '', fields)
|
|
4217
|
+
: condition.value;
|
|
4218
|
+
switch (condition.operator) {
|
|
4219
|
+
case 'eq':
|
|
4220
|
+
return left === right;
|
|
4221
|
+
case 'neq':
|
|
4222
|
+
return left !== right;
|
|
4223
|
+
case 'gt':
|
|
4224
|
+
return this.compareValues(left, right) > 0;
|
|
4225
|
+
case 'lt':
|
|
4226
|
+
return this.compareValues(left, right) < 0;
|
|
4227
|
+
case 'gte':
|
|
4228
|
+
return this.compareValues(left, right) >= 0;
|
|
4229
|
+
case 'lte':
|
|
4230
|
+
return this.compareValues(left, right) <= 0;
|
|
4231
|
+
case 'contains':
|
|
4232
|
+
return this.containsValue(left, right);
|
|
4233
|
+
case 'startsWith':
|
|
4234
|
+
return String(left ?? '').startsWith(String(right ?? ''));
|
|
4235
|
+
case 'endsWith':
|
|
4236
|
+
return String(left ?? '').endsWith(String(right ?? ''));
|
|
4237
|
+
case 'empty':
|
|
4238
|
+
return this.isEmptyValue(left);
|
|
4239
|
+
case 'notEmpty':
|
|
4240
|
+
return !this.isEmptyValue(left);
|
|
4241
|
+
case 'truthy':
|
|
4242
|
+
return !!left;
|
|
4243
|
+
default:
|
|
4244
|
+
return false;
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
compareValues(left, right) {
|
|
4248
|
+
const leftNumber = Number(left);
|
|
4249
|
+
const rightNumber = Number(right);
|
|
4250
|
+
const leftIsNumeric = Number.isFinite(leftNumber);
|
|
4251
|
+
const rightIsNumeric = Number.isFinite(rightNumber);
|
|
4252
|
+
if (leftIsNumeric && rightIsNumeric) {
|
|
4253
|
+
if (leftNumber === rightNumber)
|
|
4254
|
+
return 0;
|
|
4255
|
+
return leftNumber > rightNumber ? 1 : -1;
|
|
4256
|
+
}
|
|
4257
|
+
const leftText = String(left ?? '');
|
|
4258
|
+
const rightText = String(right ?? '');
|
|
4259
|
+
if (leftText === rightText)
|
|
4260
|
+
return 0;
|
|
4261
|
+
return leftText > rightText ? 1 : -1;
|
|
4262
|
+
}
|
|
4263
|
+
containsValue(left, right) {
|
|
4264
|
+
if (Array.isArray(left)) {
|
|
4265
|
+
return left.includes(right);
|
|
4266
|
+
}
|
|
4267
|
+
return String(left ?? '').includes(String(right ?? ''));
|
|
4268
|
+
}
|
|
4269
|
+
isEmptyValue(value) {
|
|
4270
|
+
if (value === null || value === undefined)
|
|
4271
|
+
return true;
|
|
4272
|
+
if (typeof value === 'string')
|
|
4273
|
+
return value.trim().length === 0;
|
|
4274
|
+
if (Array.isArray(value))
|
|
4275
|
+
return value.length === 0;
|
|
4276
|
+
return false;
|
|
4277
|
+
}
|
|
4278
|
+
getFieldValue(fieldId, fields) {
|
|
4279
|
+
const field = fields.find(item => item.id === fieldId);
|
|
4280
|
+
if (!field)
|
|
4281
|
+
return undefined;
|
|
4282
|
+
return this.engine.getValue(field.name);
|
|
4283
|
+
}
|
|
4022
4284
|
collectSourceValues(action, fields) {
|
|
4023
4285
|
const values = {};
|
|
4024
4286
|
const fieldIds = action.sourceFieldIds ?? [];
|
|
@@ -4495,12 +4757,15 @@ class JsonFormRendererComponent {
|
|
|
4495
4757
|
designerState;
|
|
4496
4758
|
schema;
|
|
4497
4759
|
initialValues = {};
|
|
4760
|
+
initialFieldLabels = {};
|
|
4498
4761
|
mode = 'live';
|
|
4499
4762
|
device = 'desktop';
|
|
4763
|
+
showLayoutGuides = true;
|
|
4500
4764
|
breakpoint = 'xl';
|
|
4501
4765
|
eventLogger;
|
|
4502
4766
|
eventApis = [];
|
|
4503
4767
|
eventApiExecutor;
|
|
4768
|
+
navigateToPage;
|
|
4504
4769
|
uploadOnSubmit = true;
|
|
4505
4770
|
fieldDataAccessMap;
|
|
4506
4771
|
fieldDataAccessApi;
|
|
@@ -4545,7 +4810,8 @@ class JsonFormRendererComponent {
|
|
|
4545
4810
|
}
|
|
4546
4811
|
if (changes['eventLogger']
|
|
4547
4812
|
|| changes['eventApiExecutor']
|
|
4548
|
-
|| changes['eventApis']
|
|
4813
|
+
|| changes['eventApis']
|
|
4814
|
+
|| changes['navigateToPage']) {
|
|
4549
4815
|
this.configureRunner();
|
|
4550
4816
|
}
|
|
4551
4817
|
}
|
|
@@ -4564,7 +4830,7 @@ class JsonFormRendererComponent {
|
|
|
4564
4830
|
console.warn('[ngx-form-designer] API-Only Architecture Warnings:', issues);
|
|
4565
4831
|
}
|
|
4566
4832
|
}
|
|
4567
|
-
this.engine = createFormEngine(this.schema, this.initialValues);
|
|
4833
|
+
this.engine = createFormEngine(this.schema, this.initialValues, this.initialFieldLabels);
|
|
4568
4834
|
this.syncRuntimeFieldDataAccessContext();
|
|
4569
4835
|
this.configureRunner();
|
|
4570
4836
|
// Subscribe to value changes
|
|
@@ -4617,7 +4883,8 @@ class JsonFormRendererComponent {
|
|
|
4617
4883
|
this.runner = new FormEventRunner(this.engine, {
|
|
4618
4884
|
logger: this.eventLogger,
|
|
4619
4885
|
apiExecutor,
|
|
4620
|
-
dataSourceWriter: request => this.writeEventDatasource(request)
|
|
4886
|
+
dataSourceWriter: request => this.writeEventDatasource(request),
|
|
4887
|
+
navigateToPage: this.navigateToPage
|
|
4621
4888
|
});
|
|
4622
4889
|
}
|
|
4623
4890
|
resolveEventApiExecutor() {
|
|
@@ -4916,7 +5183,8 @@ class JsonFormRendererComponent {
|
|
|
4916
5183
|
}
|
|
4917
5184
|
mapped[field.id] = {
|
|
4918
5185
|
fieldName: field.name,
|
|
4919
|
-
fieldValue: rawValue
|
|
5186
|
+
fieldValue: rawValue,
|
|
5187
|
+
...this.buildFieldLabelMetadata(field.name)
|
|
4920
5188
|
};
|
|
4921
5189
|
}
|
|
4922
5190
|
return mapped;
|
|
@@ -5003,6 +5271,12 @@ class JsonFormRendererComponent {
|
|
|
5003
5271
|
}
|
|
5004
5272
|
return [];
|
|
5005
5273
|
}
|
|
5274
|
+
buildFieldLabelMetadata(fieldName) {
|
|
5275
|
+
const fieldLabel = typeof this.engine?.getFieldLabel === 'function'
|
|
5276
|
+
? this.engine.getFieldLabel(fieldName)
|
|
5277
|
+
: undefined;
|
|
5278
|
+
return fieldLabel === undefined ? {} : { fieldLabel };
|
|
5279
|
+
}
|
|
5006
5280
|
mergeFileMetadata(target, source) {
|
|
5007
5281
|
const merged = { ...target };
|
|
5008
5282
|
for (const fieldId of Object.keys(source)) {
|
|
@@ -5085,7 +5359,7 @@ class JsonFormRendererComponent {
|
|
|
5085
5359
|
|| typeof record['type'] === 'string';
|
|
5086
5360
|
}
|
|
5087
5361
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: JsonFormRendererComponent, deps: [{ token: DesignerStateService }], target: i0.ɵɵFactoryTarget.Component });
|
|
5088
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: JsonFormRendererComponent, isStandalone: true, selector: "app-json-form-renderer", inputs: { schema: "schema", initialValues: "initialValues", mode: "mode", device: "device", breakpoint: "breakpoint", eventLogger: "eventLogger", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", uploadOnSubmit: "uploadOnSubmit", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, outputs: { valueChange: "valueChange", groupedValueChange: "groupedValueChange", combinedValueChange: "combinedValueChange", validationChange: "validationChange", uploadedFilesChange: "uploadedFilesChange", formSubmit: "formSubmit" }, usesOnChanges: true, ngImport: i0, template: `
|
|
5362
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: JsonFormRendererComponent, isStandalone: true, selector: "app-json-form-renderer", inputs: { schema: "schema", initialValues: "initialValues", initialFieldLabels: "initialFieldLabels", mode: "mode", device: "device", showLayoutGuides: "showLayoutGuides", breakpoint: "breakpoint", eventLogger: "eventLogger", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", navigateToPage: "navigateToPage", uploadOnSubmit: "uploadOnSubmit", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, outputs: { valueChange: "valueChange", groupedValueChange: "groupedValueChange", combinedValueChange: "combinedValueChange", validationChange: "validationChange", uploadedFilesChange: "uploadedFilesChange", formSubmit: "formSubmit" }, usesOnChanges: true, ngImport: i0, template: `
|
|
5089
5363
|
<div class="form-renderer-container"
|
|
5090
5364
|
data-fd="renderer"
|
|
5091
5365
|
[class.is-mobile]="device === 'mobile'"
|
|
@@ -5097,6 +5371,7 @@ class JsonFormRendererComponent {
|
|
|
5097
5371
|
[engine]="engine"
|
|
5098
5372
|
[fields]="schema.fields"
|
|
5099
5373
|
[designMode]="mode === 'design'"
|
|
5374
|
+
[showLayoutGuides]="showLayoutGuides"
|
|
5100
5375
|
[readOnlyMode]="mode === 'preview'"
|
|
5101
5376
|
[device]="device"
|
|
5102
5377
|
[breakpoint]="breakpoint"
|
|
@@ -5106,7 +5381,7 @@ class JsonFormRendererComponent {
|
|
|
5106
5381
|
</ng-container>
|
|
5107
5382
|
<ng-template #loading>Loading form...</ng-template>
|
|
5108
5383
|
</div>
|
|
5109
|
-
`, isInline: true, styles: [".form-renderer-container{width:100%;height:100vh}.form-renderer-container.is-design{padding-top:2.25rem;height:auto;overflow:visible}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LayoutNodeComponent, selector: "app-layout-node", inputs: ["node", "engine", "fields", "designMode", "readOnlyMode", "scopePath", "device", "breakpoint", "connectedDropLists"], outputs: ["nodeDrop", "nodeSelect"] }] });
|
|
5384
|
+
`, isInline: true, styles: [".form-renderer-container{width:100%;height:100vh}.form-renderer-container.is-design{padding-top:2.25rem;height:auto;overflow:visible}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LayoutNodeComponent, selector: "app-layout-node", inputs: ["node", "engine", "fields", "designMode", "showLayoutGuides", "readOnlyMode", "scopePath", "device", "breakpoint", "connectedDropLists"], outputs: ["nodeDrop", "nodeSelect"] }] });
|
|
5110
5385
|
}
|
|
5111
5386
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: JsonFormRendererComponent, decorators: [{
|
|
5112
5387
|
type: Component,
|
|
@@ -5122,6 +5397,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
5122
5397
|
[engine]="engine"
|
|
5123
5398
|
[fields]="schema.fields"
|
|
5124
5399
|
[designMode]="mode === 'design'"
|
|
5400
|
+
[showLayoutGuides]="showLayoutGuides"
|
|
5125
5401
|
[readOnlyMode]="mode === 'preview'"
|
|
5126
5402
|
[device]="device"
|
|
5127
5403
|
[breakpoint]="breakpoint"
|
|
@@ -5136,10 +5412,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
5136
5412
|
type: Input
|
|
5137
5413
|
}], initialValues: [{
|
|
5138
5414
|
type: Input
|
|
5415
|
+
}], initialFieldLabels: [{
|
|
5416
|
+
type: Input
|
|
5139
5417
|
}], mode: [{
|
|
5140
5418
|
type: Input
|
|
5141
5419
|
}], device: [{
|
|
5142
5420
|
type: Input
|
|
5421
|
+
}], showLayoutGuides: [{
|
|
5422
|
+
type: Input
|
|
5143
5423
|
}], breakpoint: [{
|
|
5144
5424
|
type: Input
|
|
5145
5425
|
}], eventLogger: [{
|
|
@@ -5148,6 +5428,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
5148
5428
|
type: Input
|
|
5149
5429
|
}], eventApiExecutor: [{
|
|
5150
5430
|
type: Input
|
|
5431
|
+
}], navigateToPage: [{
|
|
5432
|
+
type: Input
|
|
5151
5433
|
}], uploadOnSubmit: [{
|
|
5152
5434
|
type: Input
|
|
5153
5435
|
}], fieldDataAccessMap: [{
|
|
@@ -5347,8 +5629,262 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
5347
5629
|
type: Input
|
|
5348
5630
|
}] } });
|
|
5349
5631
|
|
|
5632
|
+
class FormJourneyViewerComponent {
|
|
5633
|
+
journey;
|
|
5634
|
+
viewOnly = false;
|
|
5635
|
+
eventApis = [];
|
|
5636
|
+
eventApiExecutor;
|
|
5637
|
+
initialValues;
|
|
5638
|
+
initialFieldLabels;
|
|
5639
|
+
fieldDataAccessMap;
|
|
5640
|
+
fieldDataAccessApi;
|
|
5641
|
+
formContentId;
|
|
5642
|
+
formContentVersion;
|
|
5643
|
+
formDataChange = new EventEmitter();
|
|
5644
|
+
formDataByPageChange = new EventEmitter();
|
|
5645
|
+
formValidationChange = new EventEmitter();
|
|
5646
|
+
uploadedFilesChange = new EventEmitter();
|
|
5647
|
+
submit = new EventEmitter();
|
|
5648
|
+
activePageIdChange = new EventEmitter();
|
|
5649
|
+
renderer;
|
|
5650
|
+
activePageId = signal('');
|
|
5651
|
+
values = signal({});
|
|
5652
|
+
fieldLabels = signal({});
|
|
5653
|
+
activePage = computed(() => this.journey.pages.find(page => page.id === this.activePageId()) ?? null);
|
|
5654
|
+
activePageIndex = computed(() => {
|
|
5655
|
+
const id = this.activePageId();
|
|
5656
|
+
const index = this.journey.pages.findIndex(page => page.id === id);
|
|
5657
|
+
return index >= 0 ? index : 0;
|
|
5658
|
+
});
|
|
5659
|
+
ngOnInit() {
|
|
5660
|
+
this.activePageId.set(this.journey.startPageId || this.journey.pages[0]?.id || '');
|
|
5661
|
+
this.values.set(this.normalizeInitialValues(this.initialValues));
|
|
5662
|
+
this.fieldLabels.set(this.normalizeInitialFieldLabels(this.initialFieldLabels));
|
|
5663
|
+
}
|
|
5664
|
+
ngOnChanges(changes) {
|
|
5665
|
+
if (changes['initialValues']) {
|
|
5666
|
+
this.values.set(this.normalizeInitialValues(this.initialValues));
|
|
5667
|
+
}
|
|
5668
|
+
if (changes['initialFieldLabels']) {
|
|
5669
|
+
this.fieldLabels.set(this.normalizeInitialFieldLabels(this.initialFieldLabels));
|
|
5670
|
+
}
|
|
5671
|
+
const current = this.activePageId();
|
|
5672
|
+
if (current && this.journey.pages.some(page => page.id === current))
|
|
5673
|
+
return;
|
|
5674
|
+
this.activePageId.set(this.journey.startPageId || this.journey.pages[0]?.id || '');
|
|
5675
|
+
}
|
|
5676
|
+
navigateToPage = async (pageId) => {
|
|
5677
|
+
if (!this.journey.pages.some(page => page.id === pageId)) {
|
|
5678
|
+
return { ok: false, reason: 'unknown-page' };
|
|
5679
|
+
}
|
|
5680
|
+
if (!this.viewOnly && this.renderer?.engine) {
|
|
5681
|
+
const errors = this.renderer.engine.validate();
|
|
5682
|
+
const validation = {
|
|
5683
|
+
errors: { ...errors },
|
|
5684
|
+
isValid: Object.keys(errors).length === 0
|
|
5685
|
+
};
|
|
5686
|
+
this.formValidationChange.emit(validation);
|
|
5687
|
+
if (!validation.isValid) {
|
|
5688
|
+
return { ok: false, reason: 'validation' };
|
|
5689
|
+
}
|
|
5690
|
+
}
|
|
5691
|
+
this.activePageId.set(pageId);
|
|
5692
|
+
this.activePageIdChange.emit(pageId);
|
|
5693
|
+
return { ok: true };
|
|
5694
|
+
};
|
|
5695
|
+
onValueChange(values) {
|
|
5696
|
+
const mergedScope = this.mergeValueScope(this.values(), this.toValueScope(values));
|
|
5697
|
+
const mergedFieldLabels = this.mergeFieldLabelScope(this.fieldLabels(), this.toFieldLabelScope(values));
|
|
5698
|
+
this.values.set(mergedScope);
|
|
5699
|
+
this.fieldLabels.set(mergedFieldLabels);
|
|
5700
|
+
const valuesByPage = this.toJourneyValueMapByPage(mergedScope, mergedFieldLabels);
|
|
5701
|
+
this.formDataByPageChange.emit(valuesByPage);
|
|
5702
|
+
this.formDataChange.emit(this.flattenJourneyValueMapByPage(valuesByPage));
|
|
5703
|
+
}
|
|
5704
|
+
onValidationChange(result) {
|
|
5705
|
+
this.formValidationChange.emit(result);
|
|
5706
|
+
}
|
|
5707
|
+
onUploadedFilesChange(result) {
|
|
5708
|
+
this.uploadedFilesChange.emit(result);
|
|
5709
|
+
}
|
|
5710
|
+
onSubmit(result) {
|
|
5711
|
+
this.submit.emit(result);
|
|
5712
|
+
}
|
|
5713
|
+
normalizeInitialValues(value) {
|
|
5714
|
+
if (!value)
|
|
5715
|
+
return {};
|
|
5716
|
+
return structuredClone(value);
|
|
5717
|
+
}
|
|
5718
|
+
normalizeInitialFieldLabels(value) {
|
|
5719
|
+
if (!value)
|
|
5720
|
+
return {};
|
|
5721
|
+
return structuredClone(value);
|
|
5722
|
+
}
|
|
5723
|
+
toValueScope(values) {
|
|
5724
|
+
const scope = {};
|
|
5725
|
+
for (const fieldValue of Object.values(values)) {
|
|
5726
|
+
scope[fieldValue.fieldName] = fieldValue.fieldValue;
|
|
5727
|
+
}
|
|
5728
|
+
return scope;
|
|
5729
|
+
}
|
|
5730
|
+
toFieldLabelScope(values) {
|
|
5731
|
+
const scope = {};
|
|
5732
|
+
for (const fieldValue of Object.values(values)) {
|
|
5733
|
+
if (fieldValue.fieldLabel === undefined)
|
|
5734
|
+
continue;
|
|
5735
|
+
scope[fieldValue.fieldName] = fieldValue.fieldLabel;
|
|
5736
|
+
}
|
|
5737
|
+
return scope;
|
|
5738
|
+
}
|
|
5739
|
+
mergeValueScope(currentScope, incomingScope) {
|
|
5740
|
+
return {
|
|
5741
|
+
...currentScope,
|
|
5742
|
+
...incomingScope
|
|
5743
|
+
};
|
|
5744
|
+
}
|
|
5745
|
+
mergeFieldLabelScope(currentScope, incomingScope) {
|
|
5746
|
+
return {
|
|
5747
|
+
...currentScope,
|
|
5748
|
+
...incomingScope
|
|
5749
|
+
};
|
|
5750
|
+
}
|
|
5751
|
+
toJourneyValueMapByPage(scope, fieldLabels) {
|
|
5752
|
+
const valuesByPage = {};
|
|
5753
|
+
for (const page of this.journey.pages) {
|
|
5754
|
+
const pageValues = {};
|
|
5755
|
+
for (const field of page.schema.fields) {
|
|
5756
|
+
if (!Object.prototype.hasOwnProperty.call(scope, field.name))
|
|
5757
|
+
continue;
|
|
5758
|
+
pageValues[field.id] = {
|
|
5759
|
+
fieldName: field.name,
|
|
5760
|
+
fieldValue: scope[field.name],
|
|
5761
|
+
...(fieldLabels[field.name] === undefined ? {} : { fieldLabel: fieldLabels[field.name] })
|
|
5762
|
+
};
|
|
5763
|
+
}
|
|
5764
|
+
valuesByPage[page.id] = pageValues;
|
|
5765
|
+
}
|
|
5766
|
+
return valuesByPage;
|
|
5767
|
+
}
|
|
5768
|
+
flattenJourneyValueMapByPage(valuesByPage) {
|
|
5769
|
+
const flattened = {};
|
|
5770
|
+
for (const page of this.journey.pages) {
|
|
5771
|
+
const pageValues = valuesByPage[page.id];
|
|
5772
|
+
if (!pageValues)
|
|
5773
|
+
continue;
|
|
5774
|
+
for (const [fieldId, value] of Object.entries(pageValues)) {
|
|
5775
|
+
flattened[fieldId] = value;
|
|
5776
|
+
}
|
|
5777
|
+
}
|
|
5778
|
+
return flattened;
|
|
5779
|
+
}
|
|
5780
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormJourneyViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5781
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormJourneyViewerComponent, isStandalone: true, selector: "app-form-journey-viewer", inputs: { journey: "journey", viewOnly: "viewOnly", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", initialValues: "initialValues", initialFieldLabels: "initialFieldLabels", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, outputs: { formDataChange: "formDataChange", formDataByPageChange: "formDataByPageChange", formValidationChange: "formValidationChange", uploadedFilesChange: "uploadedFilesChange", submit: "submit", activePageIdChange: "activePageIdChange" }, viewQueries: [{ propertyName: "renderer", first: true, predicate: JsonFormRendererComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
5782
|
+
<div class="form-journey-viewer flex h-full w-full flex-col" data-fd="form-journey-viewer">
|
|
5783
|
+
<div class="border-b border-gray-200 bg-white px-4 py-2 text-xs text-gray-600" data-fd="journey-progress">
|
|
5784
|
+
{{ activePageIndex() + 1 }} / {{ journey.pages.length }}
|
|
5785
|
+
<span class="ml-2 font-semibold text-gray-800">{{ activePage()?.name }}</span>
|
|
5786
|
+
</div>
|
|
5787
|
+
|
|
5788
|
+
<div class="min-h-0 flex-1" data-fd="journey-surface">
|
|
5789
|
+
<app-json-form-renderer
|
|
5790
|
+
*ngIf="activePage() as page"
|
|
5791
|
+
[schema]="page.schema"
|
|
5792
|
+
[initialValues]="values()"
|
|
5793
|
+
[initialFieldLabels]="fieldLabels()"
|
|
5794
|
+
[mode]="viewOnly ? 'preview' : 'live'"
|
|
5795
|
+
[eventApis]="eventApis"
|
|
5796
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
5797
|
+
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
5798
|
+
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
5799
|
+
[formContentId]="formContentId"
|
|
5800
|
+
[formContentVersion]="formContentVersion"
|
|
5801
|
+
[navigateToPage]="navigateToPage"
|
|
5802
|
+
(valueChange)="onValueChange($event)"
|
|
5803
|
+
(validationChange)="onValidationChange($event)"
|
|
5804
|
+
(uploadedFilesChange)="onUploadedFilesChange($event)"
|
|
5805
|
+
(formSubmit)="onSubmit($event)">
|
|
5806
|
+
</app-json-form-renderer>
|
|
5807
|
+
</div>
|
|
5808
|
+
</div>
|
|
5809
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "initialFieldLabels", "mode", "device", "showLayoutGuides", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "navigateToPage", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
|
|
5810
|
+
}
|
|
5811
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormJourneyViewerComponent, decorators: [{
|
|
5812
|
+
type: Component,
|
|
5813
|
+
args: [{
|
|
5814
|
+
selector: 'app-form-journey-viewer',
|
|
5815
|
+
standalone: true,
|
|
5816
|
+
imports: [CommonModule, JsonFormRendererComponent],
|
|
5817
|
+
template: `
|
|
5818
|
+
<div class="form-journey-viewer flex h-full w-full flex-col" data-fd="form-journey-viewer">
|
|
5819
|
+
<div class="border-b border-gray-200 bg-white px-4 py-2 text-xs text-gray-600" data-fd="journey-progress">
|
|
5820
|
+
{{ activePageIndex() + 1 }} / {{ journey.pages.length }}
|
|
5821
|
+
<span class="ml-2 font-semibold text-gray-800">{{ activePage()?.name }}</span>
|
|
5822
|
+
</div>
|
|
5823
|
+
|
|
5824
|
+
<div class="min-h-0 flex-1" data-fd="journey-surface">
|
|
5825
|
+
<app-json-form-renderer
|
|
5826
|
+
*ngIf="activePage() as page"
|
|
5827
|
+
[schema]="page.schema"
|
|
5828
|
+
[initialValues]="values()"
|
|
5829
|
+
[initialFieldLabels]="fieldLabels()"
|
|
5830
|
+
[mode]="viewOnly ? 'preview' : 'live'"
|
|
5831
|
+
[eventApis]="eventApis"
|
|
5832
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
5833
|
+
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
5834
|
+
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
5835
|
+
[formContentId]="formContentId"
|
|
5836
|
+
[formContentVersion]="formContentVersion"
|
|
5837
|
+
[navigateToPage]="navigateToPage"
|
|
5838
|
+
(valueChange)="onValueChange($event)"
|
|
5839
|
+
(validationChange)="onValidationChange($event)"
|
|
5840
|
+
(uploadedFilesChange)="onUploadedFilesChange($event)"
|
|
5841
|
+
(formSubmit)="onSubmit($event)">
|
|
5842
|
+
</app-json-form-renderer>
|
|
5843
|
+
</div>
|
|
5844
|
+
</div>
|
|
5845
|
+
`
|
|
5846
|
+
}]
|
|
5847
|
+
}], propDecorators: { journey: [{
|
|
5848
|
+
type: Input,
|
|
5849
|
+
args: [{ required: true }]
|
|
5850
|
+
}], viewOnly: [{
|
|
5851
|
+
type: Input
|
|
5852
|
+
}], eventApis: [{
|
|
5853
|
+
type: Input
|
|
5854
|
+
}], eventApiExecutor: [{
|
|
5855
|
+
type: Input
|
|
5856
|
+
}], initialValues: [{
|
|
5857
|
+
type: Input
|
|
5858
|
+
}], initialFieldLabels: [{
|
|
5859
|
+
type: Input
|
|
5860
|
+
}], fieldDataAccessMap: [{
|
|
5861
|
+
type: Input
|
|
5862
|
+
}], fieldDataAccessApi: [{
|
|
5863
|
+
type: Input
|
|
5864
|
+
}], formContentId: [{
|
|
5865
|
+
type: Input
|
|
5866
|
+
}], formContentVersion: [{
|
|
5867
|
+
type: Input
|
|
5868
|
+
}], formDataChange: [{
|
|
5869
|
+
type: Output
|
|
5870
|
+
}], formDataByPageChange: [{
|
|
5871
|
+
type: Output
|
|
5872
|
+
}], formValidationChange: [{
|
|
5873
|
+
type: Output
|
|
5874
|
+
}], uploadedFilesChange: [{
|
|
5875
|
+
type: Output
|
|
5876
|
+
}], submit: [{
|
|
5877
|
+
type: Output
|
|
5878
|
+
}], activePageIdChange: [{
|
|
5879
|
+
type: Output
|
|
5880
|
+
}], renderer: [{
|
|
5881
|
+
type: ViewChild,
|
|
5882
|
+
args: [JsonFormRendererComponent]
|
|
5883
|
+
}] } });
|
|
5884
|
+
|
|
5350
5885
|
class FormViewerComponent {
|
|
5351
5886
|
schema;
|
|
5887
|
+
journey;
|
|
5352
5888
|
set data(value) {
|
|
5353
5889
|
this._data = value ?? {};
|
|
5354
5890
|
this.refreshNormalizedInitialValues();
|
|
@@ -5376,10 +5912,13 @@ class FormViewerComponent {
|
|
|
5376
5912
|
formContentId;
|
|
5377
5913
|
formContentVersion;
|
|
5378
5914
|
formDataChange = new EventEmitter();
|
|
5915
|
+
formDataByPageChange = new EventEmitter();
|
|
5379
5916
|
formValidationChange = new EventEmitter();
|
|
5380
5917
|
uploadedFilesChange = new EventEmitter();
|
|
5381
5918
|
submit = new EventEmitter();
|
|
5919
|
+
activePageIdChange = new EventEmitter();
|
|
5382
5920
|
renderer;
|
|
5921
|
+
journeyViewer;
|
|
5383
5922
|
// Responsive State
|
|
5384
5923
|
breakpoint = signal('xl');
|
|
5385
5924
|
el = inject(ElementRef);
|
|
@@ -5389,6 +5928,7 @@ class FormViewerComponent {
|
|
|
5389
5928
|
_data = {};
|
|
5390
5929
|
_dataUsesFieldNameKeys = false;
|
|
5391
5930
|
normalizedInitialValues = {};
|
|
5931
|
+
normalizedInitialFieldLabels = {};
|
|
5392
5932
|
ngOnInit() {
|
|
5393
5933
|
this.setupResizeObserver();
|
|
5394
5934
|
}
|
|
@@ -5436,6 +5976,11 @@ class FormViewerComponent {
|
|
|
5436
5976
|
onValidationChange(result) {
|
|
5437
5977
|
this.formValidationChange.emit(result);
|
|
5438
5978
|
}
|
|
5979
|
+
onJourneyValueByPageChange(valuesByPage) {
|
|
5980
|
+
if (this.options.emitOnChange !== false) {
|
|
5981
|
+
this.formDataByPageChange.emit(valuesByPage);
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
5439
5984
|
onUploadedFilesChange(result) {
|
|
5440
5985
|
this.uploadedFilesChange.emit(result);
|
|
5441
5986
|
}
|
|
@@ -5447,14 +5992,34 @@ class FormViewerComponent {
|
|
|
5447
5992
|
// But `onSubmit` is public, let's just call it with a fake event.
|
|
5448
5993
|
if (this.renderer) {
|
|
5449
5994
|
this.renderer.onSubmit(new Event('submit'));
|
|
5995
|
+
return;
|
|
5996
|
+
}
|
|
5997
|
+
if (this.journeyViewer?.renderer) {
|
|
5998
|
+
this.journeyViewer.renderer.onSubmit(new Event('submit'));
|
|
5450
5999
|
}
|
|
5451
6000
|
}
|
|
5452
6001
|
onRendererSubmit(result) {
|
|
5453
6002
|
// Re-emit upwards
|
|
5454
6003
|
this.submit.emit(result);
|
|
5455
6004
|
}
|
|
6005
|
+
onActivePageIdChange(pageId) {
|
|
6006
|
+
this.activePageIdChange.emit(pageId);
|
|
6007
|
+
}
|
|
6008
|
+
hasJourney() {
|
|
6009
|
+
return !!this.journey && Array.isArray(this.journey.pages) && this.journey.pages.length > 0;
|
|
6010
|
+
}
|
|
6011
|
+
resolvedSchema() {
|
|
6012
|
+
if (this.schema) {
|
|
6013
|
+
return this.schema;
|
|
6014
|
+
}
|
|
6015
|
+
if (!this.hasJourney()) {
|
|
6016
|
+
return null;
|
|
6017
|
+
}
|
|
6018
|
+
return this.journey.pages[0]?.schema ?? null;
|
|
6019
|
+
}
|
|
5456
6020
|
refreshNormalizedInitialValues() {
|
|
5457
6021
|
this.normalizedInitialValues = this.normalizeInitialValues(this._data);
|
|
6022
|
+
this.normalizedInitialFieldLabels = this.normalizeInitialFieldLabels(this._data);
|
|
5458
6023
|
}
|
|
5459
6024
|
normalizeInitialValues(input) {
|
|
5460
6025
|
if (!this.isRecord(input))
|
|
@@ -5477,6 +6042,29 @@ class FormViewerComponent {
|
|
|
5477
6042
|
}
|
|
5478
6043
|
return normalized;
|
|
5479
6044
|
}
|
|
6045
|
+
normalizeInitialFieldLabels(input) {
|
|
6046
|
+
if (!this.isRecord(input))
|
|
6047
|
+
return {};
|
|
6048
|
+
if (this._dataUsesFieldNameKeys) {
|
|
6049
|
+
const normalizedFieldNameKeys = this.normalizeFieldNameKeyedLabels(input);
|
|
6050
|
+
if (normalizedFieldNameKeys) {
|
|
6051
|
+
return normalizedFieldNameKeys;
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
if (!this.isOutputShapeCandidate(input))
|
|
6055
|
+
return {};
|
|
6056
|
+
const outputValues = new Map();
|
|
6057
|
+
this.collectOutputShapeFields(input, outputValues);
|
|
6058
|
+
if (outputValues.size === 0)
|
|
6059
|
+
return {};
|
|
6060
|
+
const normalized = {};
|
|
6061
|
+
for (const [fieldName, value] of outputValues.entries()) {
|
|
6062
|
+
if (value.fieldLabel === undefined)
|
|
6063
|
+
continue;
|
|
6064
|
+
normalized[fieldName] = value.fieldLabel;
|
|
6065
|
+
}
|
|
6066
|
+
return normalized;
|
|
6067
|
+
}
|
|
5480
6068
|
normalizeFieldNameKeyedValues(input) {
|
|
5481
6069
|
if (!this.isFieldNameKeyedOutputCandidate(input)) {
|
|
5482
6070
|
return input;
|
|
@@ -5495,6 +6083,19 @@ class FormViewerComponent {
|
|
|
5495
6083
|
}
|
|
5496
6084
|
return normalized;
|
|
5497
6085
|
}
|
|
6086
|
+
normalizeFieldNameKeyedLabels(input) {
|
|
6087
|
+
if (!this.isFieldNameKeyedOutputCandidate(input)) {
|
|
6088
|
+
return null;
|
|
6089
|
+
}
|
|
6090
|
+
const normalized = {};
|
|
6091
|
+
for (const [fieldName, value] of Object.entries(input)) {
|
|
6092
|
+
if (!this.isFieldIdValue(value) || value.fieldLabel === undefined) {
|
|
6093
|
+
continue;
|
|
6094
|
+
}
|
|
6095
|
+
normalized[fieldName] = value.fieldLabel;
|
|
6096
|
+
}
|
|
6097
|
+
return normalized;
|
|
6098
|
+
}
|
|
5498
6099
|
collectOutputShapeFields(value, output) {
|
|
5499
6100
|
if (this.isFormFieldValue(value)) {
|
|
5500
6101
|
output.set(value.fieldName, value);
|
|
@@ -5585,31 +6186,56 @@ class FormViewerComponent {
|
|
|
5585
6186
|
return !!value && typeof value === 'object';
|
|
5586
6187
|
}
|
|
5587
6188
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5588
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormViewerComponent, isStandalone: true, selector: "app-form-viewer", inputs: { schema: "schema", data: "data", dataUsesFieldNameKeys: "dataUsesFieldNameKeys", options: "options", viewOnly: "viewOnly", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, outputs: { formDataChange: "formDataChange", formValidationChange: "formValidationChange", uploadedFilesChange: "uploadedFilesChange", submit: "submit" }, viewQueries: [{ propertyName: "renderer", first: true, predicate: JsonFormRendererComponent, descendants: true }], ngImport: i0, template: `
|
|
6189
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormViewerComponent, isStandalone: true, selector: "app-form-viewer", inputs: { schema: "schema", journey: "journey", data: "data", dataUsesFieldNameKeys: "dataUsesFieldNameKeys", options: "options", viewOnly: "viewOnly", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, outputs: { formDataChange: "formDataChange", formDataByPageChange: "formDataByPageChange", formValidationChange: "formValidationChange", uploadedFilesChange: "uploadedFilesChange", submit: "submit", activePageIdChange: "activePageIdChange" }, viewQueries: [{ propertyName: "renderer", first: true, predicate: JsonFormRendererComponent, descendants: true }, { propertyName: "journeyViewer", first: true, predicate: FormJourneyViewerComponent, descendants: true }], ngImport: i0, template: `
|
|
5589
6190
|
<div class="form-viewer-container flex flex-col h-full"
|
|
5590
6191
|
data-fd="form-viewer"
|
|
5591
6192
|
[attr.data-fd-mode]="viewOnly ? 'preview' : 'live'">
|
|
5592
6193
|
<div class="flex-1 min-h-0" data-fd="form-viewer-surface">
|
|
5593
|
-
<
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
6194
|
+
<ng-container *ngIf="hasJourney(); else singleFormRenderer">
|
|
6195
|
+
<app-form-journey-viewer
|
|
6196
|
+
data-fd="form-viewer-journey"
|
|
6197
|
+
[journey]="journey!"
|
|
6198
|
+
[viewOnly]="viewOnly"
|
|
6199
|
+
[eventApis]="eventApis"
|
|
6200
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
6201
|
+
[initialValues]="normalizedInitialValues"
|
|
6202
|
+
[initialFieldLabels]="normalizedInitialFieldLabels"
|
|
6203
|
+
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
6204
|
+
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
6205
|
+
[formContentId]="formContentId"
|
|
6206
|
+
[formContentVersion]="formContentVersion"
|
|
6207
|
+
(formDataChange)="onValueChange($event)"
|
|
6208
|
+
(formDataByPageChange)="onJourneyValueByPageChange($event)"
|
|
6209
|
+
(formValidationChange)="onValidationChange($event)"
|
|
6210
|
+
(submit)="onRendererSubmit($event)"
|
|
6211
|
+
(activePageIdChange)="onActivePageIdChange($event)">
|
|
6212
|
+
</app-form-journey-viewer>
|
|
6213
|
+
</ng-container>
|
|
6214
|
+
|
|
6215
|
+
<ng-template #singleFormRenderer>
|
|
6216
|
+
<app-json-form-renderer
|
|
6217
|
+
*ngIf="resolvedSchema() as currentSchema"
|
|
6218
|
+
[schema]="currentSchema"
|
|
6219
|
+
[initialValues]="normalizedInitialValues"
|
|
6220
|
+
[initialFieldLabels]="normalizedInitialFieldLabels"
|
|
6221
|
+
[mode]="viewOnly ? 'preview' : 'live'"
|
|
6222
|
+
[breakpoint]="breakpoint()"
|
|
6223
|
+
[uploadOnSubmit]="true"
|
|
6224
|
+
[eventApis]="eventApis"
|
|
6225
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
6226
|
+
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
6227
|
+
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
6228
|
+
[formContentId]="formContentId"
|
|
6229
|
+
[formContentVersion]="formContentVersion"
|
|
6230
|
+
(valueChange)="onValueChange($event)"
|
|
6231
|
+
(validationChange)="onValidationChange($event)"
|
|
6232
|
+
(uploadedFilesChange)="onUploadedFilesChange($event)"
|
|
6233
|
+
(formSubmit)="onRendererSubmit($event)">
|
|
6234
|
+
</app-json-form-renderer>
|
|
6235
|
+
</ng-template>
|
|
5610
6236
|
</div>
|
|
5611
6237
|
|
|
5612
|
-
<div *ngIf="!viewOnly && options.showSubmitButton"
|
|
6238
|
+
<div *ngIf="!viewOnly && options.showSubmitButton && !hasJourney()"
|
|
5613
6239
|
data-fd="form-viewer-submit-bar"
|
|
5614
6240
|
class="p-4 border-t border-gray-200 bg-white shadow-sm flex justify-end shrink-0 z-10">
|
|
5615
6241
|
<button
|
|
@@ -5621,35 +6247,60 @@ class FormViewerComponent {
|
|
|
5621
6247
|
</button>
|
|
5622
6248
|
</div>
|
|
5623
6249
|
</div>
|
|
5624
|
-
`, isInline: true, styles: [":host{display:block;height:100%;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6250
|
+
`, isInline: true, styles: [":host{display:block;height:100%;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "initialFieldLabels", "mode", "device", "showLayoutGuides", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "navigateToPage", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "component", type: FormJourneyViewerComponent, selector: "app-form-journey-viewer", inputs: ["journey", "viewOnly", "eventApis", "eventApiExecutor", "initialValues", "initialFieldLabels", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["formDataChange", "formDataByPageChange", "formValidationChange", "uploadedFilesChange", "submit", "activePageIdChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5625
6251
|
}
|
|
5626
6252
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormViewerComponent, decorators: [{
|
|
5627
6253
|
type: Component,
|
|
5628
|
-
args: [{ selector: 'app-form-viewer', standalone: true, imports: [CommonModule, JsonFormRendererComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
6254
|
+
args: [{ selector: 'app-form-viewer', standalone: true, imports: [CommonModule, JsonFormRendererComponent, FormJourneyViewerComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
5629
6255
|
<div class="form-viewer-container flex flex-col h-full"
|
|
5630
6256
|
data-fd="form-viewer"
|
|
5631
6257
|
[attr.data-fd-mode]="viewOnly ? 'preview' : 'live'">
|
|
5632
6258
|
<div class="flex-1 min-h-0" data-fd="form-viewer-surface">
|
|
5633
|
-
<
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
6259
|
+
<ng-container *ngIf="hasJourney(); else singleFormRenderer">
|
|
6260
|
+
<app-form-journey-viewer
|
|
6261
|
+
data-fd="form-viewer-journey"
|
|
6262
|
+
[journey]="journey!"
|
|
6263
|
+
[viewOnly]="viewOnly"
|
|
6264
|
+
[eventApis]="eventApis"
|
|
6265
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
6266
|
+
[initialValues]="normalizedInitialValues"
|
|
6267
|
+
[initialFieldLabels]="normalizedInitialFieldLabels"
|
|
6268
|
+
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
6269
|
+
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
6270
|
+
[formContentId]="formContentId"
|
|
6271
|
+
[formContentVersion]="formContentVersion"
|
|
6272
|
+
(formDataChange)="onValueChange($event)"
|
|
6273
|
+
(formDataByPageChange)="onJourneyValueByPageChange($event)"
|
|
6274
|
+
(formValidationChange)="onValidationChange($event)"
|
|
6275
|
+
(submit)="onRendererSubmit($event)"
|
|
6276
|
+
(activePageIdChange)="onActivePageIdChange($event)">
|
|
6277
|
+
</app-form-journey-viewer>
|
|
6278
|
+
</ng-container>
|
|
6279
|
+
|
|
6280
|
+
<ng-template #singleFormRenderer>
|
|
6281
|
+
<app-json-form-renderer
|
|
6282
|
+
*ngIf="resolvedSchema() as currentSchema"
|
|
6283
|
+
[schema]="currentSchema"
|
|
6284
|
+
[initialValues]="normalizedInitialValues"
|
|
6285
|
+
[initialFieldLabels]="normalizedInitialFieldLabels"
|
|
6286
|
+
[mode]="viewOnly ? 'preview' : 'live'"
|
|
6287
|
+
[breakpoint]="breakpoint()"
|
|
6288
|
+
[uploadOnSubmit]="true"
|
|
6289
|
+
[eventApis]="eventApis"
|
|
6290
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
6291
|
+
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
6292
|
+
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
6293
|
+
[formContentId]="formContentId"
|
|
6294
|
+
[formContentVersion]="formContentVersion"
|
|
6295
|
+
(valueChange)="onValueChange($event)"
|
|
6296
|
+
(validationChange)="onValidationChange($event)"
|
|
6297
|
+
(uploadedFilesChange)="onUploadedFilesChange($event)"
|
|
6298
|
+
(formSubmit)="onRendererSubmit($event)">
|
|
6299
|
+
</app-json-form-renderer>
|
|
6300
|
+
</ng-template>
|
|
5650
6301
|
</div>
|
|
5651
6302
|
|
|
5652
|
-
<div *ngIf="!viewOnly && options.showSubmitButton"
|
|
6303
|
+
<div *ngIf="!viewOnly && options.showSubmitButton && !hasJourney()"
|
|
5653
6304
|
data-fd="form-viewer-submit-bar"
|
|
5654
6305
|
class="p-4 border-t border-gray-200 bg-white shadow-sm flex justify-end shrink-0 z-10">
|
|
5655
6306
|
<button
|
|
@@ -5663,8 +6314,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
5663
6314
|
</div>
|
|
5664
6315
|
`, styles: [":host{display:block;height:100%;width:100%}\n"] }]
|
|
5665
6316
|
}], propDecorators: { schema: [{
|
|
5666
|
-
type: Input
|
|
5667
|
-
|
|
6317
|
+
type: Input
|
|
6318
|
+
}], journey: [{
|
|
6319
|
+
type: Input
|
|
5668
6320
|
}], data: [{
|
|
5669
6321
|
type: Input
|
|
5670
6322
|
}], dataUsesFieldNameKeys: [{
|
|
@@ -5687,15 +6339,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
5687
6339
|
type: Input
|
|
5688
6340
|
}], formDataChange: [{
|
|
5689
6341
|
type: Output
|
|
6342
|
+
}], formDataByPageChange: [{
|
|
6343
|
+
type: Output
|
|
5690
6344
|
}], formValidationChange: [{
|
|
5691
6345
|
type: Output
|
|
5692
6346
|
}], uploadedFilesChange: [{
|
|
5693
6347
|
type: Output
|
|
5694
6348
|
}], submit: [{
|
|
5695
6349
|
type: Output
|
|
6350
|
+
}], activePageIdChange: [{
|
|
6351
|
+
type: Output
|
|
5696
6352
|
}], renderer: [{
|
|
5697
6353
|
type: ViewChild,
|
|
5698
6354
|
args: [JsonFormRendererComponent]
|
|
6355
|
+
}], journeyViewer: [{
|
|
6356
|
+
type: ViewChild,
|
|
6357
|
+
args: [FormJourneyViewerComponent]
|
|
5699
6358
|
}] } });
|
|
5700
6359
|
|
|
5701
6360
|
class LayerTreeNodeComponent {
|
|
@@ -7021,6 +7680,7 @@ class LayoutCanvasComponent {
|
|
|
7021
7680
|
get device() { return this.state.activeDevice(); } // 'mobile' | 'desktop' for basic passing
|
|
7022
7681
|
get breakpoint() { return this.state.activeBreakpoint(); }
|
|
7023
7682
|
zoom = signal(1);
|
|
7683
|
+
showLayoutGuides = signal(true);
|
|
7024
7684
|
showLiveSchemaEditor = signal(false);
|
|
7025
7685
|
liveSchemaEditorText = signal('');
|
|
7026
7686
|
liveSchemaEditorError = signal('');
|
|
@@ -7187,6 +7847,9 @@ class LayoutCanvasComponent {
|
|
|
7187
7847
|
}
|
|
7188
7848
|
this.state.isPreviewMode.set(true);
|
|
7189
7849
|
}
|
|
7850
|
+
toggleLayoutGuides() {
|
|
7851
|
+
this.showLayoutGuides.update(current => !current);
|
|
7852
|
+
}
|
|
7190
7853
|
toggleLiveSchemaEditor() {
|
|
7191
7854
|
if (this.showLiveSchemaEditor()) {
|
|
7192
7855
|
this.closeLiveSchemaEditor();
|
|
@@ -7489,6 +8152,18 @@ class LayoutCanvasComponent {
|
|
|
7489
8152
|
|
|
7490
8153
|
<div class="w-px h-3.5 bg-border-default mx-0.5"></div>
|
|
7491
8154
|
|
|
8155
|
+
<button type="button"
|
|
8156
|
+
class="inline-flex h-7 items-center rounded-[4px] border border-transparent px-2 text-[11px] font-medium transition-colors hover:border-border-default hover:bg-slate-50"
|
|
8157
|
+
[class.bg-slate-100]="!showLayoutGuides()"
|
|
8158
|
+
[attr.aria-pressed]="!showLayoutGuides()"
|
|
8159
|
+
aria-label="Toggle layout guides"
|
|
8160
|
+
title="Toggle row and column outlines"
|
|
8161
|
+
(click)="toggleLayoutGuides(); $event.stopPropagation()">
|
|
8162
|
+
Guides
|
|
8163
|
+
</button>
|
|
8164
|
+
|
|
8165
|
+
<div class="w-px h-3.5 bg-border-default mx-0.5"></div>
|
|
8166
|
+
|
|
7492
8167
|
<button class="inline-flex h-7 items-center gap-1 rounded-[4px] bg-transparent px-1.5 transition-colors hover:bg-slate-50"
|
|
7493
8168
|
style="font-family: 'Lato', sans-serif; font-weight: 400; color: #1c2431;"
|
|
7494
8169
|
(click)="preview(); $event.stopPropagation()" title="Preview Form">
|
|
@@ -7534,6 +8209,7 @@ class LayoutCanvasComponent {
|
|
|
7534
8209
|
[schema]="schema()"
|
|
7535
8210
|
mode="design"
|
|
7536
8211
|
[device]="device"
|
|
8212
|
+
[showLayoutGuides]="showLayoutGuides()"
|
|
7537
8213
|
[breakpoint]="breakpoint">
|
|
7538
8214
|
</app-json-form-renderer>
|
|
7539
8215
|
</div>
|
|
@@ -7650,7 +8326,7 @@ class LayoutCanvasComponent {
|
|
|
7650
8326
|
|
|
7651
8327
|
<!-- Hidden file input for import -->
|
|
7652
8328
|
<input type="file" #fileInput accept=".json" (change)="onFileSelected($event)" style="display: none;">
|
|
7653
|
-
`, isInline: true, styles: [".canvas-grid{background-image:radial-gradient(rgba(148,163,184,.35) 1px,transparent 1px);background-size:18px 18px}.custom-scrollbar::-webkit-scrollbar{width:6px;height:6px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:transparent;border-radius:10px}.custom-scrollbar:hover::-webkit-scrollbar-thumb{background:#00000026}.custom-scrollbar{scrollbar-width:thin;scrollbar-color:transparent transparent}.custom-scrollbar:hover{scrollbar-color:rgba(0,0,0,.15) transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: MonacoEditorComponent, selector: "app-monaco-editor", inputs: ["value", "language", "theme", "readOnly", "minimap", "options"], outputs: ["valueChange"] }] });
|
|
8329
|
+
`, isInline: true, styles: [".canvas-grid{background-image:radial-gradient(rgba(148,163,184,.35) 1px,transparent 1px);background-size:18px 18px}.custom-scrollbar::-webkit-scrollbar{width:6px;height:6px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:transparent;border-radius:10px}.custom-scrollbar:hover::-webkit-scrollbar-thumb{background:#00000026}.custom-scrollbar{scrollbar-width:thin;scrollbar-color:transparent transparent}.custom-scrollbar:hover{scrollbar-color:rgba(0,0,0,.15) transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "initialFieldLabels", "mode", "device", "showLayoutGuides", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "navigateToPage", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: MonacoEditorComponent, selector: "app-monaco-editor", inputs: ["value", "language", "theme", "readOnly", "minimap", "options"], outputs: ["valueChange"] }] });
|
|
7654
8330
|
}
|
|
7655
8331
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutCanvasComponent, decorators: [{
|
|
7656
8332
|
type: Component,
|
|
@@ -7722,6 +8398,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
7722
8398
|
|
|
7723
8399
|
<div class="w-px h-3.5 bg-border-default mx-0.5"></div>
|
|
7724
8400
|
|
|
8401
|
+
<button type="button"
|
|
8402
|
+
class="inline-flex h-7 items-center rounded-[4px] border border-transparent px-2 text-[11px] font-medium transition-colors hover:border-border-default hover:bg-slate-50"
|
|
8403
|
+
[class.bg-slate-100]="!showLayoutGuides()"
|
|
8404
|
+
[attr.aria-pressed]="!showLayoutGuides()"
|
|
8405
|
+
aria-label="Toggle layout guides"
|
|
8406
|
+
title="Toggle row and column outlines"
|
|
8407
|
+
(click)="toggleLayoutGuides(); $event.stopPropagation()">
|
|
8408
|
+
Guides
|
|
8409
|
+
</button>
|
|
8410
|
+
|
|
8411
|
+
<div class="w-px h-3.5 bg-border-default mx-0.5"></div>
|
|
8412
|
+
|
|
7725
8413
|
<button class="inline-flex h-7 items-center gap-1 rounded-[4px] bg-transparent px-1.5 transition-colors hover:bg-slate-50"
|
|
7726
8414
|
style="font-family: 'Lato', sans-serif; font-weight: 400; color: #1c2431;"
|
|
7727
8415
|
(click)="preview(); $event.stopPropagation()" title="Preview Form">
|
|
@@ -7767,6 +8455,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
7767
8455
|
[schema]="schema()"
|
|
7768
8456
|
mode="design"
|
|
7769
8457
|
[device]="device"
|
|
8458
|
+
[showLayoutGuides]="showLayoutGuides()"
|
|
7770
8459
|
[breakpoint]="breakpoint">
|
|
7771
8460
|
</app-json-form-renderer>
|
|
7772
8461
|
</div>
|
|
@@ -8678,6 +9367,10 @@ class UiColorSwatchComponent {
|
|
|
8678
9367
|
value = '#ffffff';
|
|
8679
9368
|
valueChange = new EventEmitter();
|
|
8680
9369
|
blur = new EventEmitter();
|
|
9370
|
+
onPickerChange(color) {
|
|
9371
|
+
this.value = color;
|
|
9372
|
+
this.valueChange.emit(color);
|
|
9373
|
+
}
|
|
8681
9374
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiColorSwatchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8682
9375
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: UiColorSwatchComponent, isStandalone: true, selector: "ui-color-swatch", inputs: { label: "label", hint: "hint", helpText: "helpText", value: "value" }, outputs: { valueChange: "valueChange", blur: "blur" }, ngImport: i0, template: `
|
|
8683
9376
|
<ui-field-wrapper [label]="label" [hint]="hint" [helpText]="helpText">
|
|
@@ -8693,18 +9386,28 @@ class UiColorSwatchComponent {
|
|
|
8693
9386
|
/>
|
|
8694
9387
|
<lucide-icon name="paintbrush" class="w-4 h-4 absolute right-2 top-1/2 -translate-y-1/2 text-gray-400"></lucide-icon>
|
|
8695
9388
|
</div>
|
|
8696
|
-
<
|
|
8697
|
-
|
|
9389
|
+
<button
|
|
9390
|
+
type="button"
|
|
9391
|
+
data-testid="color-swatch-picker-trigger"
|
|
9392
|
+
class="h-9 w-9 shrink-0 cursor-pointer rounded border border-gray-200"
|
|
9393
|
+
[style.background]="value || '#ffffff'"
|
|
9394
|
+
[colorPicker]="value || '#ffffff'"
|
|
9395
|
+
[cpAlphaChannel]="'disabled'"
|
|
9396
|
+
[cpOutputFormat]="'hex'"
|
|
9397
|
+
[cpFallbackColor]="'#ffffff'"
|
|
9398
|
+
(colorPickerChange)="onPickerChange($event)"
|
|
9399
|
+
aria-label="Open color picker">
|
|
9400
|
+
</button>
|
|
8698
9401
|
</div>
|
|
8699
9402
|
</ui-field-wrapper>
|
|
8700
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: UiFieldWrapperComponent, selector: "ui-field-wrapper", inputs: ["label", "hint", "helpText"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
|
|
9403
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ColorPickerDirective, selector: "[colorPicker]", inputs: ["colorPicker", "cpWidth", "cpHeight", "cpToggle", "cpDisabled", "cpIgnoredElements", "cpFallbackColor", "cpColorMode", "cpCmykEnabled", "cpOutputFormat", "cpAlphaChannel", "cpDisableInput", "cpDialogDisplay", "cpSaveClickOutside", "cpCloseClickOutside", "cpUseRootViewContainer", "cpPosition", "cpPositionOffset", "cpPositionRelativeToArrow", "cpOKButton", "cpOKButtonText", "cpOKButtonClass", "cpCancelButton", "cpCancelButtonText", "cpCancelButtonClass", "cpEyeDropper", "cpPresetLabel", "cpPresetColors", "cpPresetColorsClass", "cpMaxPresetColorsLength", "cpPresetEmptyMessage", "cpPresetEmptyMessageClass", "cpAddColorButton", "cpAddColorButtonText", "cpAddColorButtonClass", "cpRemoveColorButtonClass", "cpArrowPosition", "cpExtraTemplate"], outputs: ["cpInputChange", "cpToggleChange", "cpSliderChange", "cpSliderDragEnd", "cpSliderDragStart", "colorPickerOpen", "colorPickerClose", "colorPickerCancel", "colorPickerSelect", "colorPickerChange", "cpCmykColorChange", "cpPresetColorsChange"], exportAs: ["ngxColorPicker"] }, { kind: "component", type: UiFieldWrapperComponent, selector: "ui-field-wrapper", inputs: ["label", "hint", "helpText"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
|
|
8701
9404
|
}
|
|
8702
9405
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiColorSwatchComponent, decorators: [{
|
|
8703
9406
|
type: Component,
|
|
8704
9407
|
args: [{
|
|
8705
9408
|
selector: 'ui-color-swatch',
|
|
8706
9409
|
standalone: true,
|
|
8707
|
-
imports: [CommonModule, FormsModule, UiFieldWrapperComponent, UiIconModule],
|
|
9410
|
+
imports: [CommonModule, FormsModule, ColorPickerDirective, UiFieldWrapperComponent, UiIconModule],
|
|
8708
9411
|
template: `
|
|
8709
9412
|
<ui-field-wrapper [label]="label" [hint]="hint" [helpText]="helpText">
|
|
8710
9413
|
<div class="flex items-center gap-2">
|
|
@@ -8719,8 +9422,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
8719
9422
|
/>
|
|
8720
9423
|
<lucide-icon name="paintbrush" class="w-4 h-4 absolute right-2 top-1/2 -translate-y-1/2 text-gray-400"></lucide-icon>
|
|
8721
9424
|
</div>
|
|
8722
|
-
<
|
|
8723
|
-
|
|
9425
|
+
<button
|
|
9426
|
+
type="button"
|
|
9427
|
+
data-testid="color-swatch-picker-trigger"
|
|
9428
|
+
class="h-9 w-9 shrink-0 cursor-pointer rounded border border-gray-200"
|
|
9429
|
+
[style.background]="value || '#ffffff'"
|
|
9430
|
+
[colorPicker]="value || '#ffffff'"
|
|
9431
|
+
[cpAlphaChannel]="'disabled'"
|
|
9432
|
+
[cpOutputFormat]="'hex'"
|
|
9433
|
+
[cpFallbackColor]="'#ffffff'"
|
|
9434
|
+
(colorPickerChange)="onPickerChange($event)"
|
|
9435
|
+
aria-label="Open color picker">
|
|
9436
|
+
</button>
|
|
8724
9437
|
</div>
|
|
8725
9438
|
</ui-field-wrapper>
|
|
8726
9439
|
`
|
|
@@ -10884,6 +11597,13 @@ class InspectorTypographySectionComponent {
|
|
|
10884
11597
|
const textDecoration = String(this.style()['textDecoration'] || '');
|
|
10885
11598
|
return textDecoration.includes('underline');
|
|
10886
11599
|
}
|
|
11600
|
+
colorValue() {
|
|
11601
|
+
const color = this.style()['color'];
|
|
11602
|
+
if (typeof color === 'string' && color.trim().length > 0) {
|
|
11603
|
+
return color;
|
|
11604
|
+
}
|
|
11605
|
+
return '#1a1b1f';
|
|
11606
|
+
}
|
|
10887
11607
|
updateStyle(key, value) {
|
|
10888
11608
|
this.styleChange.emit({ ...this.style(), [key]: value });
|
|
10889
11609
|
}
|
|
@@ -10917,14 +11637,21 @@ class InspectorTypographySectionComponent {
|
|
|
10917
11637
|
<div class="grid grid-cols-[60px_1fr] gap-2 items-center">
|
|
10918
11638
|
<label class="text-[12px] text-highlight-orange">Color</label>
|
|
10919
11639
|
<div class="flex items-center bg-input-dark border border-border-dark rounded px-2 py-1">
|
|
10920
|
-
<
|
|
10921
|
-
type="
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
11640
|
+
<button
|
|
11641
|
+
type="button"
|
|
11642
|
+
data-testid="typography-color-picker-trigger"
|
|
11643
|
+
class="mr-2 h-4 w-4 cursor-pointer rounded-sm border border-gray-300"
|
|
11644
|
+
[style.background]="colorValue()"
|
|
11645
|
+
[colorPicker]="colorValue()"
|
|
11646
|
+
[cpAlphaChannel]="'disabled'"
|
|
11647
|
+
[cpOutputFormat]="'hex'"
|
|
11648
|
+
[cpFallbackColor]="'#000000'"
|
|
11649
|
+
(colorPickerChange)="updateStyle('color', $event)"
|
|
11650
|
+
aria-label="Typography color picker">
|
|
11651
|
+
</button>
|
|
10925
11652
|
<input
|
|
10926
11653
|
type="text"
|
|
10927
|
-
[ngModel]="
|
|
11654
|
+
[ngModel]="colorValue()"
|
|
10928
11655
|
(ngModelChange)="updateStyle('color', $event)"
|
|
10929
11656
|
class="bg-transparent border-none p-0 text-sm text-gray-700 focus:ring-0 w-full">
|
|
10930
11657
|
</div>
|
|
@@ -11010,11 +11737,11 @@ class InspectorTypographySectionComponent {
|
|
|
11010
11737
|
</div>
|
|
11011
11738
|
</div>
|
|
11012
11739
|
</div>
|
|
11013
|
-
`, isInline: true, styles: [".inspector-select{height:2rem;padding-left:.5rem;padding-right:.5rem;font-size:.875rem;line-height:1.25rem;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);color:var(--color-ink-700);appearance:none;cursor:pointer}.inspector-select:focus{outline:none;border-color:var(--color-primary-blue)}.inspector-input-with-unit{display:flex;align-items:center;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);overflow:hidden}.inspector-number-input{height:2rem;padding-left:.5rem;padding-right:.5rem;background-color:transparent;border:none;font-size:.875rem;line-height:1.25rem;color:var(--color-ink-700)}.inspector-number-input:focus{outline:none}.inspector-unit{font-size:11px;color:var(--color-ink-400);padding-left:.25rem;padding-right:.25rem;background-color:var(--color-input-dark);height:2rem;display:flex;align-items:center;border-left:1px solid var(--color-border-dark)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
|
|
11740
|
+
`, isInline: true, styles: [".inspector-select{height:2rem;padding-left:.5rem;padding-right:.5rem;font-size:.875rem;line-height:1.25rem;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);color:var(--color-ink-700);appearance:none;cursor:pointer}.inspector-select:focus{outline:none;border-color:var(--color-primary-blue)}.inspector-input-with-unit{display:flex;align-items:center;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);overflow:hidden}.inspector-number-input{height:2rem;padding-left:.5rem;padding-right:.5rem;background-color:transparent;border:none;font-size:.875rem;line-height:1.25rem;color:var(--color-ink-700)}.inspector-number-input:focus{outline:none}.inspector-unit{font-size:11px;color:var(--color-ink-400);padding-left:.25rem;padding-right:.25rem;background-color:var(--color-input-dark);height:2rem;display:flex;align-items:center;border-left:1px solid var(--color-border-dark)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ColorPickerDirective, selector: "[colorPicker]", inputs: ["colorPicker", "cpWidth", "cpHeight", "cpToggle", "cpDisabled", "cpIgnoredElements", "cpFallbackColor", "cpColorMode", "cpCmykEnabled", "cpOutputFormat", "cpAlphaChannel", "cpDisableInput", "cpDialogDisplay", "cpSaveClickOutside", "cpCloseClickOutside", "cpUseRootViewContainer", "cpPosition", "cpPositionOffset", "cpPositionRelativeToArrow", "cpOKButton", "cpOKButtonText", "cpOKButtonClass", "cpCancelButton", "cpCancelButtonText", "cpCancelButtonClass", "cpEyeDropper", "cpPresetLabel", "cpPresetColors", "cpPresetColorsClass", "cpMaxPresetColorsLength", "cpPresetEmptyMessage", "cpPresetEmptyMessageClass", "cpAddColorButton", "cpAddColorButtonText", "cpAddColorButtonClass", "cpRemoveColorButtonClass", "cpArrowPosition", "cpExtraTemplate"], outputs: ["cpInputChange", "cpToggleChange", "cpSliderChange", "cpSliderDragEnd", "cpSliderDragStart", "colorPickerOpen", "colorPickerClose", "colorPickerCancel", "colorPickerSelect", "colorPickerChange", "cpCmykColorChange", "cpPresetColorsChange"], exportAs: ["ngxColorPicker"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
|
|
11014
11741
|
}
|
|
11015
11742
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InspectorTypographySectionComponent, decorators: [{
|
|
11016
11743
|
type: Component,
|
|
11017
|
-
args: [{ selector: 'inspector-typography-section', standalone: true, imports: [CommonModule, FormsModule, UiIconModule], template: `
|
|
11744
|
+
args: [{ selector: 'inspector-typography-section', standalone: true, imports: [CommonModule, FormsModule, ColorPickerDirective, UiIconModule], template: `
|
|
11018
11745
|
<div class="flex flex-col gap-3">
|
|
11019
11746
|
<div class="grid grid-cols-[60px_1fr] gap-2 items-center">
|
|
11020
11747
|
<label class="text-[12px] text-highlight-orange">Family</label>
|
|
@@ -11043,14 +11770,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
11043
11770
|
<div class="grid grid-cols-[60px_1fr] gap-2 items-center">
|
|
11044
11771
|
<label class="text-[12px] text-highlight-orange">Color</label>
|
|
11045
11772
|
<div class="flex items-center bg-input-dark border border-border-dark rounded px-2 py-1">
|
|
11046
|
-
<
|
|
11047
|
-
type="
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
|
|
11773
|
+
<button
|
|
11774
|
+
type="button"
|
|
11775
|
+
data-testid="typography-color-picker-trigger"
|
|
11776
|
+
class="mr-2 h-4 w-4 cursor-pointer rounded-sm border border-gray-300"
|
|
11777
|
+
[style.background]="colorValue()"
|
|
11778
|
+
[colorPicker]="colorValue()"
|
|
11779
|
+
[cpAlphaChannel]="'disabled'"
|
|
11780
|
+
[cpOutputFormat]="'hex'"
|
|
11781
|
+
[cpFallbackColor]="'#000000'"
|
|
11782
|
+
(colorPickerChange)="updateStyle('color', $event)"
|
|
11783
|
+
aria-label="Typography color picker">
|
|
11784
|
+
</button>
|
|
11051
11785
|
<input
|
|
11052
11786
|
type="text"
|
|
11053
|
-
[ngModel]="
|
|
11787
|
+
[ngModel]="colorValue()"
|
|
11054
11788
|
(ngModelChange)="updateStyle('color', $event)"
|
|
11055
11789
|
class="bg-transparent border-none p-0 text-sm text-gray-700 focus:ring-0 w-full">
|
|
11056
11790
|
</div>
|
|
@@ -11413,12 +12147,19 @@ class InspectorBordersSectionComponent {
|
|
|
11413
12147
|
<div class="grid grid-cols-[52px_1fr] gap-2 items-center">
|
|
11414
12148
|
<label class="section-label text-[12px]" for="inspector-border-color">Color</label>
|
|
11415
12149
|
<div class="flex min-w-0 items-center gap-2 rounded-md border border-border-dark bg-input-dark px-2 py-1">
|
|
11416
|
-
<
|
|
12150
|
+
<button
|
|
11417
12151
|
id="inspector-border-color"
|
|
11418
|
-
type="
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
12152
|
+
type="button"
|
|
12153
|
+
data-testid="border-color-picker-trigger"
|
|
12154
|
+
class="h-7 w-7 shrink-0 cursor-pointer rounded border border-border-dark bg-white"
|
|
12155
|
+
[style.background]="getColorInputValue()"
|
|
12156
|
+
[colorPicker]="getColorInputValue()"
|
|
12157
|
+
[cpAlphaChannel]="'disabled'"
|
|
12158
|
+
[cpOutputFormat]="'hex'"
|
|
12159
|
+
[cpFallbackColor]="'#000000'"
|
|
12160
|
+
(colorPickerChange)="updateStyle('borderColor', $event)"
|
|
12161
|
+
aria-label="Border color picker">
|
|
12162
|
+
</button>
|
|
11422
12163
|
|
|
11423
12164
|
<input
|
|
11424
12165
|
data-testid="border-color-input"
|
|
@@ -11433,11 +12174,11 @@ class InspectorBordersSectionComponent {
|
|
|
11433
12174
|
</div>
|
|
11434
12175
|
</div>
|
|
11435
12176
|
</div>
|
|
11436
|
-
`, isInline: true, styles: [".section-label{font-size:12px;color:var(--color-ink-400)}.inspector-input-with-unit{display:flex;align-items:center;min-width:0;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);overflow:hidden}.inspector-number-input{width:100%;min-width:0;height:2rem;padding-left:.5rem;padding-right:.5rem;background-color:transparent;border:none;color:var(--color-ink-700);font-size:.875rem;line-height:1.25rem}.inspector-number-input:focus{outline:none}.inspector-unit{display:flex;align-items:center;height:2rem;padding-left:.5rem;padding-right:.5rem;border-left:1px solid var(--color-border-dark);font-size:11px;color:var(--color-ink-400);background-color:var(--color-input-dark)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
12177
|
+
`, isInline: true, styles: [".section-label{font-size:12px;color:var(--color-ink-400)}.inspector-input-with-unit{display:flex;align-items:center;min-width:0;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);overflow:hidden}.inspector-number-input{width:100%;min-width:0;height:2rem;padding-left:.5rem;padding-right:.5rem;background-color:transparent;border:none;color:var(--color-ink-700);font-size:.875rem;line-height:1.25rem}.inspector-number-input:focus{outline:none}.inspector-unit{display:flex;align-items:center;height:2rem;padding-left:.5rem;padding-right:.5rem;border-left:1px solid var(--color-border-dark);font-size:11px;color:var(--color-ink-400);background-color:var(--color-input-dark)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ColorPickerDirective, selector: "[colorPicker]", inputs: ["colorPicker", "cpWidth", "cpHeight", "cpToggle", "cpDisabled", "cpIgnoredElements", "cpFallbackColor", "cpColorMode", "cpCmykEnabled", "cpOutputFormat", "cpAlphaChannel", "cpDisableInput", "cpDialogDisplay", "cpSaveClickOutside", "cpCloseClickOutside", "cpUseRootViewContainer", "cpPosition", "cpPositionOffset", "cpPositionRelativeToArrow", "cpOKButton", "cpOKButtonText", "cpOKButtonClass", "cpCancelButton", "cpCancelButtonText", "cpCancelButtonClass", "cpEyeDropper", "cpPresetLabel", "cpPresetColors", "cpPresetColorsClass", "cpMaxPresetColorsLength", "cpPresetEmptyMessage", "cpPresetEmptyMessageClass", "cpAddColorButton", "cpAddColorButtonText", "cpAddColorButtonClass", "cpRemoveColorButtonClass", "cpArrowPosition", "cpExtraTemplate"], outputs: ["cpInputChange", "cpToggleChange", "cpSliderChange", "cpSliderDragEnd", "cpSliderDragStart", "colorPickerOpen", "colorPickerClose", "colorPickerCancel", "colorPickerSelect", "colorPickerChange", "cpCmykColorChange", "cpPresetColorsChange"], exportAs: ["ngxColorPicker"] }] });
|
|
11437
12178
|
}
|
|
11438
12179
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InspectorBordersSectionComponent, decorators: [{
|
|
11439
12180
|
type: Component,
|
|
11440
|
-
args: [{ selector: 'inspector-borders-section', standalone: true, imports: [CommonModule, FormsModule], template: `
|
|
12181
|
+
args: [{ selector: 'inspector-borders-section', standalone: true, imports: [CommonModule, FormsModule, ColorPickerDirective], template: `
|
|
11441
12182
|
<div class="flex flex-col gap-4">
|
|
11442
12183
|
<div class="grid grid-cols-[56px_1fr] gap-3 items-start">
|
|
11443
12184
|
<span class="section-label text-[12px] pt-2">Radius</span>
|
|
@@ -11530,12 +12271,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
11530
12271
|
<div class="grid grid-cols-[52px_1fr] gap-2 items-center">
|
|
11531
12272
|
<label class="section-label text-[12px]" for="inspector-border-color">Color</label>
|
|
11532
12273
|
<div class="flex min-w-0 items-center gap-2 rounded-md border border-border-dark bg-input-dark px-2 py-1">
|
|
11533
|
-
<
|
|
12274
|
+
<button
|
|
11534
12275
|
id="inspector-border-color"
|
|
11535
|
-
type="
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
12276
|
+
type="button"
|
|
12277
|
+
data-testid="border-color-picker-trigger"
|
|
12278
|
+
class="h-7 w-7 shrink-0 cursor-pointer rounded border border-border-dark bg-white"
|
|
12279
|
+
[style.background]="getColorInputValue()"
|
|
12280
|
+
[colorPicker]="getColorInputValue()"
|
|
12281
|
+
[cpAlphaChannel]="'disabled'"
|
|
12282
|
+
[cpOutputFormat]="'hex'"
|
|
12283
|
+
[cpFallbackColor]="'#000000'"
|
|
12284
|
+
(colorPickerChange)="updateStyle('borderColor', $event)"
|
|
12285
|
+
aria-label="Border color picker">
|
|
12286
|
+
</button>
|
|
11539
12287
|
|
|
11540
12288
|
<input
|
|
11541
12289
|
data-testid="border-color-input"
|
|
@@ -12066,19 +12814,57 @@ class InspectorBackgroundsSectionComponent {
|
|
|
12066
12814
|
{ label: 'Right', value: 'right' }
|
|
12067
12815
|
];
|
|
12068
12816
|
showImageUrl = false;
|
|
12817
|
+
backgroundColorValue() {
|
|
12818
|
+
return this.normalizeBackgroundColor(this.style()['backgroundColor']);
|
|
12819
|
+
}
|
|
12069
12820
|
getBackgroundPreview() {
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
return bg;
|
|
12821
|
+
return this.backgroundColorValue();
|
|
12822
|
+
}
|
|
12823
|
+
onBackgroundPickerChange(value) {
|
|
12824
|
+
this.updateStyle('backgroundColor', this.normalizeBackgroundColor(value));
|
|
12825
|
+
}
|
|
12826
|
+
onBackgroundColorInputChange(value) {
|
|
12827
|
+
this.updateStyle('backgroundColor', this.normalizeBackgroundColor(value));
|
|
12078
12828
|
}
|
|
12079
12829
|
updateStyle(key, value) {
|
|
12080
12830
|
this.styleChange.emit({ ...this.style(), [key]: value });
|
|
12081
12831
|
}
|
|
12832
|
+
normalizeBackgroundColor(value) {
|
|
12833
|
+
if (typeof value !== 'string')
|
|
12834
|
+
return '#ffffff';
|
|
12835
|
+
const trimmed = value.trim();
|
|
12836
|
+
if (!trimmed)
|
|
12837
|
+
return '#ffffff';
|
|
12838
|
+
if (this.isTransparentColor(trimmed))
|
|
12839
|
+
return '#ffffff';
|
|
12840
|
+
return trimmed;
|
|
12841
|
+
}
|
|
12842
|
+
isTransparentColor(value) {
|
|
12843
|
+
const compact = value.replace(/\s+/g, '').toLowerCase();
|
|
12844
|
+
if (compact === 'transparent')
|
|
12845
|
+
return true;
|
|
12846
|
+
if (compact.startsWith('rgba(') && compact.endsWith(')')) {
|
|
12847
|
+
const parts = compact.slice(5, -1).split(',');
|
|
12848
|
+
if (parts.length === 4) {
|
|
12849
|
+
const alpha = Number.parseFloat(parts[3]);
|
|
12850
|
+
return Number.isFinite(alpha) && alpha === 0;
|
|
12851
|
+
}
|
|
12852
|
+
}
|
|
12853
|
+
if (compact.startsWith('hsla(') && compact.endsWith(')')) {
|
|
12854
|
+
const parts = compact.slice(5, -1).split(',');
|
|
12855
|
+
if (parts.length === 4) {
|
|
12856
|
+
const alpha = Number.parseFloat(parts[3]);
|
|
12857
|
+
return Number.isFinite(alpha) && alpha === 0;
|
|
12858
|
+
}
|
|
12859
|
+
}
|
|
12860
|
+
if (/^#[0-9a-f]{4}$/i.test(compact)) {
|
|
12861
|
+
return compact[4] === '0';
|
|
12862
|
+
}
|
|
12863
|
+
if (/^#[0-9a-f]{8}$/i.test(compact)) {
|
|
12864
|
+
return compact.endsWith('00');
|
|
12865
|
+
}
|
|
12866
|
+
return false;
|
|
12867
|
+
}
|
|
12082
12868
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InspectorBackgroundsSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12083
12869
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: InspectorBackgroundsSectionComponent, isStandalone: true, selector: "inspector-backgrounds-section", inputs: { style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { styleChange: "styleChange" }, ngImport: i0, template: `
|
|
12084
12870
|
<div class="flex flex-col gap-3">
|
|
@@ -12092,13 +12878,22 @@ class InspectorBackgroundsSectionComponent {
|
|
|
12092
12878
|
<div class="grid grid-cols-[60px_1fr] gap-2 items-center">
|
|
12093
12879
|
<label class="text-[11px] text-gray-500">Color</label>
|
|
12094
12880
|
<div class="flex items-center bg-input-dark border border-border-dark rounded px-2 py-1">
|
|
12095
|
-
<
|
|
12096
|
-
|
|
12097
|
-
|
|
12881
|
+
<button
|
|
12882
|
+
type="button"
|
|
12883
|
+
data-testid="background-color-picker-trigger"
|
|
12884
|
+
class="mr-2 h-4 w-4 cursor-pointer rounded-sm border border-gray-300 overflow-hidden"
|
|
12885
|
+
[style.background]="getBackgroundPreview()"
|
|
12886
|
+
[colorPicker]="backgroundColorValue()"
|
|
12887
|
+
[cpAlphaChannel]="'disabled'"
|
|
12888
|
+
[cpOutputFormat]="'hex'"
|
|
12889
|
+
[cpFallbackColor]="'#ffffff'"
|
|
12890
|
+
(colorPickerChange)="onBackgroundPickerChange($event)"
|
|
12891
|
+
aria-label="Background color picker">
|
|
12892
|
+
</button>
|
|
12098
12893
|
<input
|
|
12099
12894
|
type="text"
|
|
12100
|
-
[ngModel]="
|
|
12101
|
-
(ngModelChange)="
|
|
12895
|
+
[ngModel]="backgroundColorValue()"
|
|
12896
|
+
(ngModelChange)="onBackgroundColorInputChange($event)"
|
|
12102
12897
|
class="bg-transparent border-none p-0 text-xs text-gray-700 focus:ring-0 w-full">
|
|
12103
12898
|
</div>
|
|
12104
12899
|
</div>
|
|
@@ -12135,11 +12930,11 @@ class InspectorBackgroundsSectionComponent {
|
|
|
12135
12930
|
</div>
|
|
12136
12931
|
}
|
|
12137
12932
|
</div>
|
|
12138
|
-
`, isInline: true, styles: [".inspector-input{height:1.75rem;padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);color:var(--color-ink-700)}.inspector-input:focus{outline:none;border-color:var(--color-primary-blue)}.inspector-select{height:1.75rem;padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);color:var(--color-ink-700);appearance:none;cursor:pointer}.inspector-select:focus{outline:none;border-color:var(--color-primary-blue)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
|
|
12933
|
+
`, isInline: true, styles: [".inspector-input{height:1.75rem;padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);color:var(--color-ink-700)}.inspector-input:focus{outline:none;border-color:var(--color-primary-blue)}.inspector-select{height:1.75rem;padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);color:var(--color-ink-700);appearance:none;cursor:pointer}.inspector-select:focus{outline:none;border-color:var(--color-primary-blue)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ColorPickerDirective, selector: "[colorPicker]", inputs: ["colorPicker", "cpWidth", "cpHeight", "cpToggle", "cpDisabled", "cpIgnoredElements", "cpFallbackColor", "cpColorMode", "cpCmykEnabled", "cpOutputFormat", "cpAlphaChannel", "cpDisableInput", "cpDialogDisplay", "cpSaveClickOutside", "cpCloseClickOutside", "cpUseRootViewContainer", "cpPosition", "cpPositionOffset", "cpPositionRelativeToArrow", "cpOKButton", "cpOKButtonText", "cpOKButtonClass", "cpCancelButton", "cpCancelButtonText", "cpCancelButtonClass", "cpEyeDropper", "cpPresetLabel", "cpPresetColors", "cpPresetColorsClass", "cpMaxPresetColorsLength", "cpPresetEmptyMessage", "cpPresetEmptyMessageClass", "cpAddColorButton", "cpAddColorButtonText", "cpAddColorButtonClass", "cpRemoveColorButtonClass", "cpArrowPosition", "cpExtraTemplate"], outputs: ["cpInputChange", "cpToggleChange", "cpSliderChange", "cpSliderDragEnd", "cpSliderDragStart", "colorPickerOpen", "colorPickerClose", "colorPickerCancel", "colorPickerSelect", "colorPickerChange", "cpCmykColorChange", "cpPresetColorsChange"], exportAs: ["ngxColorPicker"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
|
|
12139
12934
|
}
|
|
12140
12935
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InspectorBackgroundsSectionComponent, decorators: [{
|
|
12141
12936
|
type: Component,
|
|
12142
|
-
args: [{ selector: 'inspector-backgrounds-section', standalone: true, imports: [CommonModule, FormsModule, UiIconModule], template: `
|
|
12937
|
+
args: [{ selector: 'inspector-backgrounds-section', standalone: true, imports: [CommonModule, FormsModule, ColorPickerDirective, UiIconModule], template: `
|
|
12143
12938
|
<div class="flex flex-col gap-3">
|
|
12144
12939
|
<!-- Image & Gradient -->
|
|
12145
12940
|
<div class="flex justify-between items-center group cursor-pointer py-1">
|
|
@@ -12151,13 +12946,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
12151
12946
|
<div class="grid grid-cols-[60px_1fr] gap-2 items-center">
|
|
12152
12947
|
<label class="text-[11px] text-gray-500">Color</label>
|
|
12153
12948
|
<div class="flex items-center bg-input-dark border border-border-dark rounded px-2 py-1">
|
|
12154
|
-
<
|
|
12155
|
-
|
|
12156
|
-
|
|
12949
|
+
<button
|
|
12950
|
+
type="button"
|
|
12951
|
+
data-testid="background-color-picker-trigger"
|
|
12952
|
+
class="mr-2 h-4 w-4 cursor-pointer rounded-sm border border-gray-300 overflow-hidden"
|
|
12953
|
+
[style.background]="getBackgroundPreview()"
|
|
12954
|
+
[colorPicker]="backgroundColorValue()"
|
|
12955
|
+
[cpAlphaChannel]="'disabled'"
|
|
12956
|
+
[cpOutputFormat]="'hex'"
|
|
12957
|
+
[cpFallbackColor]="'#ffffff'"
|
|
12958
|
+
(colorPickerChange)="onBackgroundPickerChange($event)"
|
|
12959
|
+
aria-label="Background color picker">
|
|
12960
|
+
</button>
|
|
12157
12961
|
<input
|
|
12158
12962
|
type="text"
|
|
12159
|
-
[ngModel]="
|
|
12160
|
-
(ngModelChange)="
|
|
12963
|
+
[ngModel]="backgroundColorValue()"
|
|
12964
|
+
(ngModelChange)="onBackgroundColorInputChange($event)"
|
|
12161
12965
|
class="bg-transparent border-none p-0 text-xs text-gray-700 focus:ring-0 w-full">
|
|
12162
12966
|
</div>
|
|
12163
12967
|
</div>
|
|
@@ -18135,6 +18939,9 @@ class FormPreviewComponent {
|
|
|
18135
18939
|
fieldDataAccessApi;
|
|
18136
18940
|
formContentId;
|
|
18137
18941
|
formContentVersion;
|
|
18942
|
+
pages = [];
|
|
18943
|
+
activePageId = null;
|
|
18944
|
+
pageSelect = new EventEmitter();
|
|
18138
18945
|
breakpoints = ['xs', 'sm', 'md', 'lg', 'xl', '2xl'];
|
|
18139
18946
|
breakpoint = signal('xl');
|
|
18140
18947
|
// Derived device type for renderer compatibility
|
|
@@ -18149,6 +18956,25 @@ class FormPreviewComponent {
|
|
|
18149
18956
|
setBreakpoint(bp) {
|
|
18150
18957
|
this.breakpoint.set(bp);
|
|
18151
18958
|
}
|
|
18959
|
+
hasJourneyPages() {
|
|
18960
|
+
return this.pages.length > 1;
|
|
18961
|
+
}
|
|
18962
|
+
isPageActive(pageId) {
|
|
18963
|
+
return this.resolveActivePageId() === pageId;
|
|
18964
|
+
}
|
|
18965
|
+
requestPageSelect(pageId) {
|
|
18966
|
+
if (this.resolveActivePageId() === pageId)
|
|
18967
|
+
return;
|
|
18968
|
+
this.pageSelect.emit(pageId);
|
|
18969
|
+
}
|
|
18970
|
+
navigateToPage = async (pageId) => {
|
|
18971
|
+
const targetPageId = pageId?.trim();
|
|
18972
|
+
if (!targetPageId || !this.pages.some(page => page.id === targetPageId)) {
|
|
18973
|
+
return { ok: false, reason: 'unknown-page' };
|
|
18974
|
+
}
|
|
18975
|
+
this.requestPageSelect(targetPageId);
|
|
18976
|
+
return { ok: true };
|
|
18977
|
+
};
|
|
18152
18978
|
getContainerWidth() {
|
|
18153
18979
|
const bp = this.breakpoint();
|
|
18154
18980
|
switch (bp) {
|
|
@@ -18237,8 +19063,16 @@ class FormPreviewComponent {
|
|
|
18237
19063
|
return false;
|
|
18238
19064
|
return /^[A-Za-z0-9+/]+={0,2}$/.test(value);
|
|
18239
19065
|
}
|
|
19066
|
+
trackPageById(_, page) {
|
|
19067
|
+
return page.id;
|
|
19068
|
+
}
|
|
19069
|
+
resolveActivePageId() {
|
|
19070
|
+
if (this.activePageId)
|
|
19071
|
+
return this.activePageId;
|
|
19072
|
+
return this.pages[0]?.id ?? '';
|
|
19073
|
+
}
|
|
18240
19074
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormPreviewComponent, deps: [{ token: DesignerStateService }], target: i0.ɵɵFactoryTarget.Component });
|
|
18241
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormPreviewComponent, isStandalone: true, selector: "app-form-preview", inputs: { eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, ngImport: i0, template: `
|
|
19075
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormPreviewComponent, isStandalone: true, selector: "app-form-preview", inputs: { eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion", pages: "pages", activePageId: "activePageId" }, outputs: { pageSelect: "pageSelect" }, ngImport: i0, template: `
|
|
18242
19076
|
<div class="fixed inset-0 bg-white z-[100] flex flex-col animate-in fade-in duration-200">
|
|
18243
19077
|
<!-- Toolbar -->
|
|
18244
19078
|
<div class="h-14 border-b border-gray-200 flex items-center justify-between px-4 bg-white shadow-sm shrink-0">
|
|
@@ -18269,6 +19103,28 @@ class FormPreviewComponent {
|
|
|
18269
19103
|
|
|
18270
19104
|
<!-- Content Area -->
|
|
18271
19105
|
<div class="flex-1 flex overflow-hidden bg-gray-50">
|
|
19106
|
+
<aside *ngIf="hasJourneyPages()" class="w-64 shrink-0 border-r border-gray-200 bg-white flex flex-col">
|
|
19107
|
+
<div class="px-4 py-3 border-b border-gray-200">
|
|
19108
|
+
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500">Journey</div>
|
|
19109
|
+
<div class="mt-1 text-xs text-gray-500">Switch preview page</div>
|
|
19110
|
+
</div>
|
|
19111
|
+
<div class="flex-1 overflow-y-auto p-2">
|
|
19112
|
+
<button
|
|
19113
|
+
*ngFor="let page of pages; trackBy: trackPageById"
|
|
19114
|
+
type="button"
|
|
19115
|
+
class="mb-2 w-full rounded-md border px-3 py-2 text-left transition-colors"
|
|
19116
|
+
[class.border-blue-200]="isPageActive(page.id)"
|
|
19117
|
+
[class.bg-blue-50]="isPageActive(page.id)"
|
|
19118
|
+
[class.text-blue-700]="isPageActive(page.id)"
|
|
19119
|
+
[class.border-gray-200]="!isPageActive(page.id)"
|
|
19120
|
+
[class.bg-white]="!isPageActive(page.id)"
|
|
19121
|
+
[class.text-gray-700]="!isPageActive(page.id)"
|
|
19122
|
+
(click)="requestPageSelect(page.id)">
|
|
19123
|
+
<div class="text-xs font-semibold truncate">{{ page.name }}</div>
|
|
19124
|
+
<div class="mt-0.5 text-[10px] text-gray-500 truncate">{{ page.route }}</div>
|
|
19125
|
+
</button>
|
|
19126
|
+
</div>
|
|
19127
|
+
</aside>
|
|
18272
19128
|
|
|
18273
19129
|
<!-- LEFT: Form Render Area -->
|
|
18274
19130
|
<div class="flex-1 overflow-auto flex justify-center items-start p-8 relative">
|
|
@@ -18290,6 +19146,7 @@ class FormPreviewComponent {
|
|
|
18290
19146
|
[breakpoint]="breakpoint()"
|
|
18291
19147
|
[eventApis]="eventApis"
|
|
18292
19148
|
[eventApiExecutor]="eventApiExecutor"
|
|
19149
|
+
[navigateToPage]="navigateToPage"
|
|
18293
19150
|
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
18294
19151
|
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
18295
19152
|
[formContentId]="formContentId"
|
|
@@ -18318,7 +19175,7 @@ class FormPreviewComponent {
|
|
|
18318
19175
|
</div>
|
|
18319
19176
|
</div>
|
|
18320
19177
|
</div>
|
|
18321
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
|
|
19178
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "initialFieldLabels", "mode", "device", "showLayoutGuides", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "navigateToPage", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
|
|
18322
19179
|
}
|
|
18323
19180
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormPreviewComponent, decorators: [{
|
|
18324
19181
|
type: Component,
|
|
@@ -18357,6 +19214,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18357
19214
|
|
|
18358
19215
|
<!-- Content Area -->
|
|
18359
19216
|
<div class="flex-1 flex overflow-hidden bg-gray-50">
|
|
19217
|
+
<aside *ngIf="hasJourneyPages()" class="w-64 shrink-0 border-r border-gray-200 bg-white flex flex-col">
|
|
19218
|
+
<div class="px-4 py-3 border-b border-gray-200">
|
|
19219
|
+
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500">Journey</div>
|
|
19220
|
+
<div class="mt-1 text-xs text-gray-500">Switch preview page</div>
|
|
19221
|
+
</div>
|
|
19222
|
+
<div class="flex-1 overflow-y-auto p-2">
|
|
19223
|
+
<button
|
|
19224
|
+
*ngFor="let page of pages; trackBy: trackPageById"
|
|
19225
|
+
type="button"
|
|
19226
|
+
class="mb-2 w-full rounded-md border px-3 py-2 text-left transition-colors"
|
|
19227
|
+
[class.border-blue-200]="isPageActive(page.id)"
|
|
19228
|
+
[class.bg-blue-50]="isPageActive(page.id)"
|
|
19229
|
+
[class.text-blue-700]="isPageActive(page.id)"
|
|
19230
|
+
[class.border-gray-200]="!isPageActive(page.id)"
|
|
19231
|
+
[class.bg-white]="!isPageActive(page.id)"
|
|
19232
|
+
[class.text-gray-700]="!isPageActive(page.id)"
|
|
19233
|
+
(click)="requestPageSelect(page.id)">
|
|
19234
|
+
<div class="text-xs font-semibold truncate">{{ page.name }}</div>
|
|
19235
|
+
<div class="mt-0.5 text-[10px] text-gray-500 truncate">{{ page.route }}</div>
|
|
19236
|
+
</button>
|
|
19237
|
+
</div>
|
|
19238
|
+
</aside>
|
|
18360
19239
|
|
|
18361
19240
|
<!-- LEFT: Form Render Area -->
|
|
18362
19241
|
<div class="flex-1 overflow-auto flex justify-center items-start p-8 relative">
|
|
@@ -18378,6 +19257,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18378
19257
|
[breakpoint]="breakpoint()"
|
|
18379
19258
|
[eventApis]="eventApis"
|
|
18380
19259
|
[eventApiExecutor]="eventApiExecutor"
|
|
19260
|
+
[navigateToPage]="navigateToPage"
|
|
18381
19261
|
[fieldDataAccessMap]="fieldDataAccessMap"
|
|
18382
19262
|
[fieldDataAccessApi]="fieldDataAccessApi"
|
|
18383
19263
|
[formContentId]="formContentId"
|
|
@@ -18420,6 +19300,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18420
19300
|
type: Input
|
|
18421
19301
|
}], formContentVersion: [{
|
|
18422
19302
|
type: Input
|
|
19303
|
+
}], pages: [{
|
|
19304
|
+
type: Input
|
|
19305
|
+
}], activePageId: [{
|
|
19306
|
+
type: Input
|
|
19307
|
+
}], pageSelect: [{
|
|
19308
|
+
type: Output
|
|
18423
19309
|
}] } });
|
|
18424
19310
|
|
|
18425
19311
|
class JsonFormDesignerComponent {
|
|
@@ -18427,6 +19313,14 @@ class JsonFormDesignerComponent {
|
|
|
18427
19313
|
mode = 'edit';
|
|
18428
19314
|
eventApis = [];
|
|
18429
19315
|
eventApiExecutor;
|
|
19316
|
+
pages = null;
|
|
19317
|
+
activePageId = null;
|
|
19318
|
+
canRemovePage = false;
|
|
19319
|
+
pageAdd = new EventEmitter();
|
|
19320
|
+
pageSelect = new EventEmitter();
|
|
19321
|
+
pageRemove = new EventEmitter();
|
|
19322
|
+
pageRename = new EventEmitter();
|
|
19323
|
+
pageRouteChange = new EventEmitter();
|
|
18430
19324
|
state = inject(DesignerStateService);
|
|
18431
19325
|
ngOnInit() {
|
|
18432
19326
|
this.state.setFlavor(this.flavor);
|
|
@@ -18446,7 +19340,7 @@ class JsonFormDesignerComponent {
|
|
|
18446
19340
|
}
|
|
18447
19341
|
}
|
|
18448
19342
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: JsonFormDesignerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18449
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: JsonFormDesignerComponent, isStandalone: true, selector: "app-json-form-designer", inputs: { flavor: "flavor", mode: "mode", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor" }, host: { classAttribute: "fd-designer-host block h-full w-full" }, usesOnChanges: true, ngImport: i0, template: `
|
|
19343
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: JsonFormDesignerComponent, isStandalone: true, selector: "app-json-form-designer", inputs: { flavor: "flavor", mode: "mode", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", pages: "pages", activePageId: "activePageId", canRemovePage: "canRemovePage" }, outputs: { pageAdd: "pageAdd", pageSelect: "pageSelect", pageRemove: "pageRemove", pageRename: "pageRename", pageRouteChange: "pageRouteChange" }, host: { classAttribute: "fd-designer-host block h-full w-full" }, usesOnChanges: true, ngImport: i0, template: `
|
|
18450
19344
|
<div
|
|
18451
19345
|
class="fd-designer flex h-full w-full overflow-hidden relative"
|
|
18452
19346
|
data-fd="designer"
|
|
@@ -18459,7 +19353,16 @@ class JsonFormDesignerComponent {
|
|
|
18459
19353
|
[style.opacity]="state.isLeftPanelCollapsed() ? '0' : '1'"
|
|
18460
19354
|
[class.border-none]="state.isLeftPanelCollapsed()">
|
|
18461
19355
|
<div class="h-full" [class.pointer-events-none]="state.isLeftPanelCollapsed()">
|
|
18462
|
-
<app-field-palette
|
|
19356
|
+
<app-field-palette
|
|
19357
|
+
[pages]="pages"
|
|
19358
|
+
[activePageId]="activePageId"
|
|
19359
|
+
[canRemovePage]="canRemovePage"
|
|
19360
|
+
(pageAdd)="pageAdd.emit()"
|
|
19361
|
+
(pageSelect)="pageSelect.emit($event)"
|
|
19362
|
+
(pageRemove)="pageRemove.emit($event)"
|
|
19363
|
+
(pageRename)="pageRename.emit($event)"
|
|
19364
|
+
(pageRouteChange)="pageRouteChange.emit($event)">
|
|
19365
|
+
</app-field-palette>
|
|
18463
19366
|
</div>
|
|
18464
19367
|
</div>
|
|
18465
19368
|
|
|
@@ -18479,11 +19382,14 @@ class JsonFormDesignerComponent {
|
|
|
18479
19382
|
class="fd-designer-preview"
|
|
18480
19383
|
data-fd-region="preview"
|
|
18481
19384
|
*ngIf="state.isPreviewMode()"
|
|
19385
|
+
[pages]="pages ?? []"
|
|
19386
|
+
[activePageId]="activePageId"
|
|
18482
19387
|
[eventApis]="eventApis"
|
|
18483
|
-
[eventApiExecutor]="eventApiExecutor"
|
|
19388
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
19389
|
+
(pageSelect)="pageSelect.emit($event)">
|
|
18484
19390
|
</app-form-preview>
|
|
18485
19391
|
</div>
|
|
18486
|
-
`, isInline: true, styles: [".custom-scrollbar::-webkit-scrollbar{width:4px;height:4px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:transparent;border-radius:10px}.custom-scrollbar:hover::-webkit-scrollbar-thumb{background:#00000026}.custom-scrollbar{scrollbar-width:thin;scrollbar-color:transparent transparent}.custom-scrollbar:hover{scrollbar-color:rgba(0,0,0,.15) transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview", inputs: ["eventApis", "eventApiExecutor", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"] }] });
|
|
19392
|
+
`, isInline: true, styles: [".custom-scrollbar::-webkit-scrollbar{width:4px;height:4px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:transparent;border-radius:10px}.custom-scrollbar:hover::-webkit-scrollbar-thumb{background:#00000026}.custom-scrollbar{scrollbar-width:thin;scrollbar-color:transparent transparent}.custom-scrollbar:hover{scrollbar-color:rgba(0,0,0,.15) transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview", inputs: ["eventApis", "eventApiExecutor", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "pages", "activePageId"], outputs: ["pageSelect"] }] });
|
|
18487
19393
|
}
|
|
18488
19394
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: JsonFormDesignerComponent, decorators: [{
|
|
18489
19395
|
type: Component,
|
|
@@ -18502,7 +19408,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18502
19408
|
[style.opacity]="state.isLeftPanelCollapsed() ? '0' : '1'"
|
|
18503
19409
|
[class.border-none]="state.isLeftPanelCollapsed()">
|
|
18504
19410
|
<div class="h-full" [class.pointer-events-none]="state.isLeftPanelCollapsed()">
|
|
18505
|
-
<app-field-palette
|
|
19411
|
+
<app-field-palette
|
|
19412
|
+
[pages]="pages"
|
|
19413
|
+
[activePageId]="activePageId"
|
|
19414
|
+
[canRemovePage]="canRemovePage"
|
|
19415
|
+
(pageAdd)="pageAdd.emit()"
|
|
19416
|
+
(pageSelect)="pageSelect.emit($event)"
|
|
19417
|
+
(pageRemove)="pageRemove.emit($event)"
|
|
19418
|
+
(pageRename)="pageRename.emit($event)"
|
|
19419
|
+
(pageRouteChange)="pageRouteChange.emit($event)">
|
|
19420
|
+
</app-field-palette>
|
|
18506
19421
|
</div>
|
|
18507
19422
|
</div>
|
|
18508
19423
|
|
|
@@ -18522,8 +19437,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18522
19437
|
class="fd-designer-preview"
|
|
18523
19438
|
data-fd-region="preview"
|
|
18524
19439
|
*ngIf="state.isPreviewMode()"
|
|
19440
|
+
[pages]="pages ?? []"
|
|
19441
|
+
[activePageId]="activePageId"
|
|
18525
19442
|
[eventApis]="eventApis"
|
|
18526
|
-
[eventApiExecutor]="eventApiExecutor"
|
|
19443
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
19444
|
+
(pageSelect)="pageSelect.emit($event)">
|
|
18527
19445
|
</app-form-preview>
|
|
18528
19446
|
</div>
|
|
18529
19447
|
`, styles: [".custom-scrollbar::-webkit-scrollbar{width:4px;height:4px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:transparent;border-radius:10px}.custom-scrollbar:hover::-webkit-scrollbar-thumb{background:#00000026}.custom-scrollbar{scrollbar-width:thin;scrollbar-color:transparent transparent}.custom-scrollbar:hover{scrollbar-color:rgba(0,0,0,.15) transparent}\n"] }]
|
|
@@ -18535,6 +19453,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18535
19453
|
type: Input
|
|
18536
19454
|
}], eventApiExecutor: [{
|
|
18537
19455
|
type: Input
|
|
19456
|
+
}], pages: [{
|
|
19457
|
+
type: Input
|
|
19458
|
+
}], activePageId: [{
|
|
19459
|
+
type: Input
|
|
19460
|
+
}], canRemovePage: [{
|
|
19461
|
+
type: Input
|
|
19462
|
+
}], pageAdd: [{
|
|
19463
|
+
type: Output
|
|
19464
|
+
}], pageSelect: [{
|
|
19465
|
+
type: Output
|
|
19466
|
+
}], pageRemove: [{
|
|
19467
|
+
type: Output
|
|
19468
|
+
}], pageRename: [{
|
|
19469
|
+
type: Output
|
|
19470
|
+
}], pageRouteChange: [{
|
|
19471
|
+
type: Output
|
|
18538
19472
|
}] } });
|
|
18539
19473
|
|
|
18540
19474
|
// ---------------------------------------------------------------------------
|
|
@@ -19734,115 +20668,80 @@ const FORM_DESIGNER_AI_TOOL_PLUGIN = {
|
|
|
19734
20668
|
],
|
|
19735
20669
|
};
|
|
19736
20670
|
|
|
19737
|
-
class
|
|
19738
|
-
|
|
19739
|
-
|
|
19740
|
-
|
|
19741
|
-
|
|
19742
|
-
toolByName;
|
|
19743
|
-
constructor() {
|
|
19744
|
-
this.state = inject(DesignerStateService);
|
|
19745
|
-
const injectedWidgetDefs = inject(WIDGET_DEFINITIONS, { optional: true }) ?? [];
|
|
19746
|
-
this.widgetDefs = injectedWidgetDefs.flat();
|
|
19747
|
-
this.eventApis = [];
|
|
19748
|
-
this.plugins = [FORM_DESIGNER_AI_TOOL_PLUGIN];
|
|
19749
|
-
this.toolByName = this.buildToolIndex(this.plugins);
|
|
19750
|
-
}
|
|
19751
|
-
/**
|
|
19752
|
-
* Create an instance directly for testing without Angular DI.
|
|
19753
|
-
*/
|
|
19754
|
-
static forTest(state, eventApis, plugins, widgetDefs) {
|
|
19755
|
-
const instance = Object.create(AiToolRegistryService.prototype);
|
|
19756
|
-
instance.state = state;
|
|
19757
|
-
instance.eventApis = eventApis ? [...eventApis] : [];
|
|
19758
|
-
instance.widgetDefs = widgetDefs ? [...widgetDefs] : [];
|
|
19759
|
-
instance.plugins = plugins?.length ? [...plugins] : [FORM_DESIGNER_AI_TOOL_PLUGIN];
|
|
19760
|
-
instance.toolByName = instance.buildToolIndex(instance.plugins);
|
|
19761
|
-
return instance;
|
|
19762
|
-
}
|
|
19763
|
-
describeTools() {
|
|
19764
|
-
return this.plugins.flatMap((plugin) => plugin.tools.map((tool) => ({
|
|
19765
|
-
name: tool.name,
|
|
19766
|
-
description: tool.summary,
|
|
19767
|
-
summary: tool.summary,
|
|
19768
|
-
domain: tool.domain,
|
|
19769
|
-
readOnly: tool.readOnly,
|
|
19770
|
-
tags: tool.tags,
|
|
19771
|
-
whenToUse: tool.whenToUse,
|
|
19772
|
-
whenNotToUse: tool.whenNotToUse,
|
|
19773
|
-
exampleIntents: tool.exampleIntents,
|
|
19774
|
-
requiresSelection: tool.requiresSelection,
|
|
19775
|
-
requiresCapabilities: tool.requiresCapabilities,
|
|
19776
|
-
requiredAuthScopes: tool.requiredAuthScopes,
|
|
19777
|
-
parametersSchema: tool.parametersSchema,
|
|
19778
|
-
})));
|
|
20671
|
+
class FormDesignerAiFeatureStateService {
|
|
20672
|
+
widgetDefinitions = (inject(WIDGET_DEFINITIONS, { optional: true }) ?? []).flat();
|
|
20673
|
+
eventApisSignal = signal([]);
|
|
20674
|
+
setEventApis(apis) {
|
|
20675
|
+
this.eventApisSignal.set([...apis]);
|
|
19779
20676
|
}
|
|
19780
|
-
|
|
19781
|
-
|
|
19782
|
-
|
|
19783
|
-
|
|
19784
|
-
|
|
19785
|
-
|
|
19786
|
-
error: `Unknown tool: "${name}"`,
|
|
19787
|
-
};
|
|
19788
|
-
}
|
|
19789
|
-
const context = this.createContext();
|
|
19790
|
-
if (tool.isApplicable && !tool.isApplicable(context)) {
|
|
19791
|
-
return {
|
|
19792
|
-
ok: false,
|
|
19793
|
-
result: null,
|
|
19794
|
-
error: `Tool "${name}" is not applicable in current context.`,
|
|
19795
|
-
};
|
|
19796
|
-
}
|
|
19797
|
-
const result = await tool.execute(context, args);
|
|
19798
|
-
return result;
|
|
20677
|
+
createToolContext(state) {
|
|
20678
|
+
return {
|
|
20679
|
+
state,
|
|
20680
|
+
eventApis: this.eventApisSignal(),
|
|
20681
|
+
widgetDefs: this.widgetDefinitions,
|
|
20682
|
+
};
|
|
19799
20683
|
}
|
|
19800
|
-
|
|
20684
|
+
createDiscoveryContext(state) {
|
|
19801
20685
|
return {
|
|
19802
20686
|
workspace: 'designer',
|
|
19803
|
-
readOnly:
|
|
19804
|
-
hasSelection: !!
|
|
20687
|
+
readOnly: state.isReadOnly(),
|
|
20688
|
+
hasSelection: !!state.selectedNodeId(),
|
|
19805
20689
|
capabilities: {
|
|
19806
|
-
eventApis: this.
|
|
19807
|
-
widgetCatalog: this.
|
|
20690
|
+
eventApis: this.eventApisSignal().length > 0,
|
|
20691
|
+
widgetCatalog: this.widgetDefinitions.length > 0,
|
|
19808
20692
|
},
|
|
19809
20693
|
};
|
|
19810
20694
|
}
|
|
19811
|
-
|
|
19812
|
-
|
|
19813
|
-
this.eventApis = [...apis];
|
|
19814
|
-
}
|
|
19815
|
-
/** Allow host/shell to update widget catalog at runtime. */
|
|
19816
|
-
setWidgetDefinitions(widgetDefs) {
|
|
19817
|
-
this.widgetDefs = [...widgetDefs];
|
|
19818
|
-
}
|
|
19819
|
-
/** Register additional plain TS plugins without requiring Angular DI contracts. */
|
|
19820
|
-
registerPlugin(plugin) {
|
|
19821
|
-
this.plugins = [...this.plugins, plugin];
|
|
19822
|
-
this.toolByName = this.buildToolIndex(this.plugins);
|
|
19823
|
-
}
|
|
19824
|
-
createContext() {
|
|
19825
|
-
return {
|
|
19826
|
-
state: this.state,
|
|
19827
|
-
eventApis: this.eventApis,
|
|
19828
|
-
widgetDefs: this.widgetDefs,
|
|
19829
|
-
};
|
|
19830
|
-
}
|
|
19831
|
-
buildToolIndex(plugins) {
|
|
19832
|
-
const index = new Map();
|
|
19833
|
-
for (const plugin of plugins) {
|
|
19834
|
-
for (const tool of plugin.tools) {
|
|
19835
|
-
index.set(tool.name, tool);
|
|
19836
|
-
}
|
|
19837
|
-
}
|
|
19838
|
-
return index;
|
|
19839
|
-
}
|
|
19840
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AiToolRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
19841
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AiToolRegistryService });
|
|
20695
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormDesignerAiFeatureStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
20696
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormDesignerAiFeatureStateService });
|
|
19842
20697
|
}
|
|
19843
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type:
|
|
20698
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormDesignerAiFeatureStateService, decorators: [{
|
|
19844
20699
|
type: Injectable
|
|
19845
|
-
}]
|
|
20700
|
+
}] });
|
|
20701
|
+
function bindFormDesignerTools(getContext) {
|
|
20702
|
+
return FORM_DESIGNER_AI_TOOL_PLUGIN.tools.map((tool) => defineAiTool({
|
|
20703
|
+
name: tool.name,
|
|
20704
|
+
summary: tool.summary,
|
|
20705
|
+
domain: tool.domain,
|
|
20706
|
+
readOnly: tool.readOnly,
|
|
20707
|
+
tags: tool.tags,
|
|
20708
|
+
whenToUse: tool.whenToUse,
|
|
20709
|
+
whenNotToUse: tool.whenNotToUse,
|
|
20710
|
+
exampleIntents: tool.exampleIntents,
|
|
20711
|
+
requiresSelection: tool.requiresSelection,
|
|
20712
|
+
requiresCapabilities: tool.requiresCapabilities,
|
|
20713
|
+
requiredAuthScopes: tool.requiredAuthScopes,
|
|
20714
|
+
parametersSchema: tool.parametersSchema,
|
|
20715
|
+
isApplicable: tool.isApplicable ? () => tool.isApplicable(getContext()) : undefined,
|
|
20716
|
+
execute: async (args) => {
|
|
20717
|
+
const result = await tool.execute(getContext(), args);
|
|
20718
|
+
return result;
|
|
20719
|
+
},
|
|
20720
|
+
}));
|
|
20721
|
+
}
|
|
20722
|
+
function buildFormDesignerSystemPrompt(state) {
|
|
20723
|
+
const mode = state.isReadOnly() ? 'read-only' : 'editable';
|
|
20724
|
+
return [
|
|
20725
|
+
'You are assisting with a JSON form designer workspace.',
|
|
20726
|
+
`The current designer session is ${mode}.`,
|
|
20727
|
+
'Prefer the registered tools for inspecting and editing the form schema instead of describing hypothetical changes.',
|
|
20728
|
+
'Keep responses concise and grounded in the current schema state.',
|
|
20729
|
+
].join(' ');
|
|
20730
|
+
}
|
|
20731
|
+
function provideFormDesignerAngaiFeature() {
|
|
20732
|
+
return [
|
|
20733
|
+
FormDesignerAiFeatureStateService,
|
|
20734
|
+
...provideAngaiFeature(() => {
|
|
20735
|
+
const state = inject(DesignerStateService);
|
|
20736
|
+
const featureState = inject(FormDesignerAiFeatureStateService);
|
|
20737
|
+
return {
|
|
20738
|
+
tools: bindFormDesignerTools(() => featureState.createToolContext(state)),
|
|
20739
|
+
discoveryContext: () => featureState.createDiscoveryContext(state),
|
|
20740
|
+
systemPrompt: () => buildFormDesignerSystemPrompt(state),
|
|
20741
|
+
};
|
|
20742
|
+
}),
|
|
20743
|
+
];
|
|
20744
|
+
}
|
|
19846
20745
|
|
|
19847
20746
|
const parseTemplateSchema = (schema) => {
|
|
19848
20747
|
return parseSchema(JSON.stringify(schema));
|
|
@@ -21588,6 +22487,622 @@ const TRANSACTION_KYC_REVIEW_TEMPLATE = {
|
|
|
21588
22487
|
}
|
|
21589
22488
|
};
|
|
21590
22489
|
const TRANSACTION_KYC_REVIEW_SCHEMA = parseTemplateSchema(TRANSACTION_KYC_REVIEW_TEMPLATE);
|
|
22490
|
+
const JOURNEY_BRANCHING_TEMPLATE_STEP_ONE = {
|
|
22491
|
+
"id": "template-journey-branch-step-1",
|
|
22492
|
+
"version": "1.0.0",
|
|
22493
|
+
"schemaVersion": "1.0.0",
|
|
22494
|
+
"flavor": "form",
|
|
22495
|
+
"title": "Step 1 · Intake + Routing",
|
|
22496
|
+
"metadata": {
|
|
22497
|
+
"example": true,
|
|
22498
|
+
"scenario": "journey-branching",
|
|
22499
|
+
"page": "intake"
|
|
22500
|
+
},
|
|
22501
|
+
"fields": [
|
|
22502
|
+
{
|
|
22503
|
+
"id": "fld_search_country",
|
|
22504
|
+
"widgetId": "core.form:search",
|
|
22505
|
+
"name": "branchSearchTerm",
|
|
22506
|
+
"type": "search",
|
|
22507
|
+
"label": "Search Country",
|
|
22508
|
+
"placeholder": "Type country code or name",
|
|
22509
|
+
"dataConfig": {
|
|
22510
|
+
"type": "source",
|
|
22511
|
+
"datasourceId": "journey_branch_ds_country_search",
|
|
22512
|
+
"labelKey": "label",
|
|
22513
|
+
"valueKey": "value",
|
|
22514
|
+
"searchColumns": ["label", "value", "region"],
|
|
22515
|
+
"optionsLimit": 30
|
|
22516
|
+
},
|
|
22517
|
+
"events": [
|
|
22518
|
+
{
|
|
22519
|
+
"id": "evt_search_country",
|
|
22520
|
+
"on": "change",
|
|
22521
|
+
"enabled": true,
|
|
22522
|
+
"actions": [
|
|
22523
|
+
{
|
|
22524
|
+
"type": "api",
|
|
22525
|
+
"apiId": "api.country.search",
|
|
22526
|
+
"datasourceId": "journey_branch_ds_country_search",
|
|
22527
|
+
"sourceFieldIds": ["fld_search_country"],
|
|
22528
|
+
"inputTransformScript": "const query = String(context.formValues.branchSearchTerm ?? \"\").trim(); return { query };",
|
|
22529
|
+
"outputTransformScript": "return Array.isArray(output?.items) ? output.items.map(item => ({ label: item.name, value: item.code, region: item.region })) : [];"
|
|
22530
|
+
}
|
|
22531
|
+
]
|
|
22532
|
+
}
|
|
22533
|
+
]
|
|
22534
|
+
},
|
|
22535
|
+
{
|
|
22536
|
+
"id": "fld_country",
|
|
22537
|
+
"widgetId": "core.form:select",
|
|
22538
|
+
"name": "countryCode",
|
|
22539
|
+
"type": "select",
|
|
22540
|
+
"label": "Country",
|
|
22541
|
+
"placeholder": "Select a country",
|
|
22542
|
+
"dataConfig": {
|
|
22543
|
+
"type": "source",
|
|
22544
|
+
"datasourceId": "journey_branch_ds_country_search",
|
|
22545
|
+
"labelKey": "label",
|
|
22546
|
+
"valueKey": "value",
|
|
22547
|
+
"searchEnabled": false,
|
|
22548
|
+
"optionsLimit": 30
|
|
22549
|
+
},
|
|
22550
|
+
"events": [
|
|
22551
|
+
{
|
|
22552
|
+
"id": "evt_country_cities",
|
|
22553
|
+
"on": "change",
|
|
22554
|
+
"enabled": true,
|
|
22555
|
+
"actions": [
|
|
22556
|
+
{
|
|
22557
|
+
"type": "api",
|
|
22558
|
+
"apiId": "api.country.cities",
|
|
22559
|
+
"datasourceId": "journey_branch_ds_country_cities",
|
|
22560
|
+
"sourceFieldIds": ["fld_country"],
|
|
22561
|
+
"inputTransformScript": "const countryCode = String(context.formValues.countryCode ?? context.event.value ?? \"\"); return { countryCode };",
|
|
22562
|
+
"outputTransformScript": "return Array.isArray(output?.cities) ? output.cities.map(city => ({ cityCode: city.code, cityName: city.name, population: city.population, weather: city.weather })) : [];"
|
|
22563
|
+
}
|
|
22564
|
+
]
|
|
22565
|
+
}
|
|
22566
|
+
]
|
|
22567
|
+
},
|
|
22568
|
+
{
|
|
22569
|
+
"id": "fld_priority_route",
|
|
22570
|
+
"widgetId": "core.form:checkbox",
|
|
22571
|
+
"name": "priorityRoute",
|
|
22572
|
+
"type": "checkbox",
|
|
22573
|
+
"label": "High priority route (skip to page 3)"
|
|
22574
|
+
},
|
|
22575
|
+
{
|
|
22576
|
+
"id": "btn_continue",
|
|
22577
|
+
"widgetId": "core.form:form-button",
|
|
22578
|
+
"name": "continueWithBranch",
|
|
22579
|
+
"type": "form-button",
|
|
22580
|
+
"label": "Continue",
|
|
22581
|
+
"variant": "primary",
|
|
22582
|
+
"buttonType": "button",
|
|
22583
|
+
"events": [
|
|
22584
|
+
{
|
|
22585
|
+
"id": "evt_continue_with_branch",
|
|
22586
|
+
"on": "click",
|
|
22587
|
+
"enabled": true,
|
|
22588
|
+
"actions": [
|
|
22589
|
+
{
|
|
22590
|
+
"type": "api",
|
|
22591
|
+
"apiId": "api.country.profile",
|
|
22592
|
+
"datasourceId": "journey_branch_ds_country_profile",
|
|
22593
|
+
"sourceFieldIds": ["fld_country"],
|
|
22594
|
+
"inputTransformScript": "const countryCode = String(context.formValues.countryCode ?? \"\"); return { countryCode };",
|
|
22595
|
+
"outputTransformScript": "if (!output || typeof output !== \"object\") return []; return [{ countryCode: output.code, currency: output.currency, timezone: output.timezone, nextHoliday: output.nextHoliday, supportTime: output.supportTime }];"
|
|
22596
|
+
},
|
|
22597
|
+
{
|
|
22598
|
+
"type": "navigate",
|
|
22599
|
+
"targetPageId": "page-details",
|
|
22600
|
+
"when": {
|
|
22601
|
+
"operator": "AND",
|
|
22602
|
+
"conditions": [
|
|
22603
|
+
{ "fieldId": "fld_country", "operator": "notEmpty" },
|
|
22604
|
+
{ "fieldId": "fld_priority_route", "operator": "truthy" }
|
|
22605
|
+
]
|
|
22606
|
+
}
|
|
22607
|
+
},
|
|
22608
|
+
{
|
|
22609
|
+
"type": "navigate",
|
|
22610
|
+
"targetPageId": "page-preferences",
|
|
22611
|
+
"when": {
|
|
22612
|
+
"operator": "AND",
|
|
22613
|
+
"conditions": [
|
|
22614
|
+
{ "fieldId": "fld_country", "operator": "notEmpty" },
|
|
22615
|
+
{ "fieldId": "fld_priority_route", "operator": "eq", "value": false }
|
|
22616
|
+
]
|
|
22617
|
+
}
|
|
22618
|
+
}
|
|
22619
|
+
]
|
|
22620
|
+
}
|
|
22621
|
+
]
|
|
22622
|
+
}
|
|
22623
|
+
],
|
|
22624
|
+
"layout": {
|
|
22625
|
+
"id": "layout_step_1_root",
|
|
22626
|
+
"type": "col",
|
|
22627
|
+
"responsive": { "xs": 12 },
|
|
22628
|
+
"children": [
|
|
22629
|
+
{
|
|
22630
|
+
"id": "row_step_1_inputs",
|
|
22631
|
+
"type": "row",
|
|
22632
|
+
"children": [
|
|
22633
|
+
{
|
|
22634
|
+
"id": "col_step_1_search",
|
|
22635
|
+
"type": "col",
|
|
22636
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
22637
|
+
"children": [
|
|
22638
|
+
{ "id": "w_step_1_search", "type": "widget", "widgetKind": "field", "refId": "fld_search_country" }
|
|
22639
|
+
]
|
|
22640
|
+
},
|
|
22641
|
+
{
|
|
22642
|
+
"id": "col_step_1_country",
|
|
22643
|
+
"type": "col",
|
|
22644
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
22645
|
+
"children": [
|
|
22646
|
+
{ "id": "w_step_1_country", "type": "widget", "widgetKind": "field", "refId": "fld_country" }
|
|
22647
|
+
]
|
|
22648
|
+
}
|
|
22649
|
+
]
|
|
22650
|
+
},
|
|
22651
|
+
{
|
|
22652
|
+
"id": "row_step_1_priority",
|
|
22653
|
+
"type": "row",
|
|
22654
|
+
"children": [
|
|
22655
|
+
{
|
|
22656
|
+
"id": "col_step_1_priority",
|
|
22657
|
+
"type": "col",
|
|
22658
|
+
"responsive": { "xs": 12 },
|
|
22659
|
+
"children": [
|
|
22660
|
+
{ "id": "w_step_1_priority", "type": "widget", "widgetKind": "field", "refId": "fld_priority_route" }
|
|
22661
|
+
]
|
|
22662
|
+
}
|
|
22663
|
+
]
|
|
22664
|
+
},
|
|
22665
|
+
{
|
|
22666
|
+
"id": "row_step_1_continue",
|
|
22667
|
+
"type": "row",
|
|
22668
|
+
"children": [
|
|
22669
|
+
{
|
|
22670
|
+
"id": "col_step_1_continue",
|
|
22671
|
+
"type": "col",
|
|
22672
|
+
"responsive": { "xs": 12 },
|
|
22673
|
+
"children": [
|
|
22674
|
+
{ "id": "w_step_1_continue", "type": "widget", "widgetKind": "button", "refId": "btn_continue" }
|
|
22675
|
+
]
|
|
22676
|
+
}
|
|
22677
|
+
]
|
|
22678
|
+
}
|
|
22679
|
+
]
|
|
22680
|
+
}
|
|
22681
|
+
};
|
|
22682
|
+
const JOURNEY_BRANCHING_TEMPLATE_STEP_TWO = {
|
|
22683
|
+
"id": "template-journey-branch-step-2",
|
|
22684
|
+
"version": "1.0.0",
|
|
22685
|
+
"schemaVersion": "1.0.0",
|
|
22686
|
+
"flavor": "form",
|
|
22687
|
+
"title": "Step 2 · Preferences",
|
|
22688
|
+
"metadata": {
|
|
22689
|
+
"example": true,
|
|
22690
|
+
"scenario": "journey-branching",
|
|
22691
|
+
"page": "preferences"
|
|
22692
|
+
},
|
|
22693
|
+
"fields": [
|
|
22694
|
+
{
|
|
22695
|
+
"id": "fld_full_name",
|
|
22696
|
+
"widgetId": "core.form:text",
|
|
22697
|
+
"name": "fullName",
|
|
22698
|
+
"type": "text",
|
|
22699
|
+
"label": "Contact Name",
|
|
22700
|
+
"placeholder": "Enter contact name"
|
|
22701
|
+
},
|
|
22702
|
+
{
|
|
22703
|
+
"id": "fld_email",
|
|
22704
|
+
"widgetId": "core.form:email",
|
|
22705
|
+
"name": "email",
|
|
22706
|
+
"type": "email",
|
|
22707
|
+
"label": "Contact Email",
|
|
22708
|
+
"placeholder": "Enter contact email"
|
|
22709
|
+
},
|
|
22710
|
+
{
|
|
22711
|
+
"id": "fld_contact_method",
|
|
22712
|
+
"widgetId": "core.form:radio",
|
|
22713
|
+
"name": "contactMethod",
|
|
22714
|
+
"type": "radio",
|
|
22715
|
+
"label": "Preferred Contact Method",
|
|
22716
|
+
"staticOptions": [
|
|
22717
|
+
{ "label": "Email", "value": "email" },
|
|
22718
|
+
{ "label": "Phone", "value": "phone" },
|
|
22719
|
+
{ "label": "SMS", "value": "sms" }
|
|
22720
|
+
]
|
|
22721
|
+
},
|
|
22722
|
+
{
|
|
22723
|
+
"id": "fld_summary_country_code",
|
|
22724
|
+
"widgetId": "core.form:text",
|
|
22725
|
+
"name": "summaryCountryCode",
|
|
22726
|
+
"type": "text",
|
|
22727
|
+
"label": "Country Code",
|
|
22728
|
+
"readonly": true,
|
|
22729
|
+
"dataConfig": {
|
|
22730
|
+
"type": "source",
|
|
22731
|
+
"datasourceId": "journey_branch_ds_country_profile",
|
|
22732
|
+
"valueKey": "countryCode"
|
|
22733
|
+
}
|
|
22734
|
+
},
|
|
22735
|
+
{
|
|
22736
|
+
"id": "tbl_city_snapshot",
|
|
22737
|
+
"widgetId": "core.web:table",
|
|
22738
|
+
"name": "summaryCityTable",
|
|
22739
|
+
"type": "table",
|
|
22740
|
+
"label": "Available Cities",
|
|
22741
|
+
"compact": false,
|
|
22742
|
+
"striped": true,
|
|
22743
|
+
"columns": [
|
|
22744
|
+
{ "key": "cityName", "label": "City" },
|
|
22745
|
+
{ "key": "population", "label": "Population" },
|
|
22746
|
+
{ "key": "weather", "label": "Weather" }
|
|
22747
|
+
],
|
|
22748
|
+
"dataConfig": {
|
|
22749
|
+
"type": "source",
|
|
22750
|
+
"datasourceId": "journey_branch_ds_country_cities",
|
|
22751
|
+
"searchEnabled": false,
|
|
22752
|
+
"pageSize": 5,
|
|
22753
|
+
"sort": [{ "column": "cityName", "dir": "asc" }]
|
|
22754
|
+
}
|
|
22755
|
+
},
|
|
22756
|
+
{
|
|
22757
|
+
"id": "btn_back_intake",
|
|
22758
|
+
"widgetId": "core.form:form-button",
|
|
22759
|
+
"name": "backToIntake",
|
|
22760
|
+
"type": "form-button",
|
|
22761
|
+
"label": "Back to Intake",
|
|
22762
|
+
"variant": "secondary",
|
|
22763
|
+
"buttonType": "button",
|
|
22764
|
+
"events": [
|
|
22765
|
+
{
|
|
22766
|
+
"id": "evt_back_to_intake",
|
|
22767
|
+
"on": "click",
|
|
22768
|
+
"enabled": true,
|
|
22769
|
+
"actions": [
|
|
22770
|
+
{ "type": "navigate", "targetPageId": "page-intake" }
|
|
22771
|
+
]
|
|
22772
|
+
}
|
|
22773
|
+
]
|
|
22774
|
+
},
|
|
22775
|
+
{
|
|
22776
|
+
"id": "btn_continue_details",
|
|
22777
|
+
"widgetId": "core.form:form-button",
|
|
22778
|
+
"name": "continueToDetails",
|
|
22779
|
+
"type": "form-button",
|
|
22780
|
+
"label": "Continue to Details",
|
|
22781
|
+
"variant": "primary",
|
|
22782
|
+
"buttonType": "button",
|
|
22783
|
+
"events": [
|
|
22784
|
+
{
|
|
22785
|
+
"id": "evt_continue_to_details",
|
|
22786
|
+
"on": "click",
|
|
22787
|
+
"enabled": true,
|
|
22788
|
+
"actions": [
|
|
22789
|
+
{
|
|
22790
|
+
"type": "navigate",
|
|
22791
|
+
"targetPageId": "page-details",
|
|
22792
|
+
"when": {
|
|
22793
|
+
"operator": "AND",
|
|
22794
|
+
"conditions": [
|
|
22795
|
+
{ "fieldId": "fld_full_name", "operator": "notEmpty" },
|
|
22796
|
+
{ "fieldId": "fld_email", "operator": "notEmpty" }
|
|
22797
|
+
]
|
|
22798
|
+
}
|
|
22799
|
+
}
|
|
22800
|
+
]
|
|
22801
|
+
}
|
|
22802
|
+
]
|
|
22803
|
+
}
|
|
22804
|
+
],
|
|
22805
|
+
"layout": {
|
|
22806
|
+
"id": "layout_step_2_root",
|
|
22807
|
+
"type": "col",
|
|
22808
|
+
"responsive": { "xs": 12 },
|
|
22809
|
+
"children": [
|
|
22810
|
+
{
|
|
22811
|
+
"id": "row_step_2_inputs",
|
|
22812
|
+
"type": "row",
|
|
22813
|
+
"children": [
|
|
22814
|
+
{
|
|
22815
|
+
"id": "col_step_2_name",
|
|
22816
|
+
"type": "col",
|
|
22817
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
22818
|
+
"children": [
|
|
22819
|
+
{ "id": "w_step_2_name", "type": "widget", "widgetKind": "field", "refId": "fld_full_name" }
|
|
22820
|
+
]
|
|
22821
|
+
},
|
|
22822
|
+
{
|
|
22823
|
+
"id": "col_step_2_email",
|
|
22824
|
+
"type": "col",
|
|
22825
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
22826
|
+
"children": [
|
|
22827
|
+
{ "id": "w_step_2_email", "type": "widget", "widgetKind": "field", "refId": "fld_email" }
|
|
22828
|
+
]
|
|
22829
|
+
}
|
|
22830
|
+
]
|
|
22831
|
+
},
|
|
22832
|
+
{
|
|
22833
|
+
"id": "row_step_2_summary",
|
|
22834
|
+
"type": "row",
|
|
22835
|
+
"children": [
|
|
22836
|
+
{
|
|
22837
|
+
"id": "col_step_2_contact_method",
|
|
22838
|
+
"type": "col",
|
|
22839
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
22840
|
+
"children": [
|
|
22841
|
+
{ "id": "w_step_2_contact_method", "type": "widget", "widgetKind": "field", "refId": "fld_contact_method" }
|
|
22842
|
+
]
|
|
22843
|
+
},
|
|
22844
|
+
{
|
|
22845
|
+
"id": "col_step_2_country_code",
|
|
22846
|
+
"type": "col",
|
|
22847
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
22848
|
+
"children": [
|
|
22849
|
+
{ "id": "w_step_2_country_code", "type": "widget", "widgetKind": "field", "refId": "fld_summary_country_code" }
|
|
22850
|
+
]
|
|
22851
|
+
}
|
|
22852
|
+
]
|
|
22853
|
+
},
|
|
22854
|
+
{
|
|
22855
|
+
"id": "row_step_2_table",
|
|
22856
|
+
"type": "row",
|
|
22857
|
+
"children": [
|
|
22858
|
+
{
|
|
22859
|
+
"id": "col_step_2_table",
|
|
22860
|
+
"type": "col",
|
|
22861
|
+
"responsive": { "xs": 12 },
|
|
22862
|
+
"children": [
|
|
22863
|
+
{ "id": "w_step_2_table", "type": "widget", "widgetKind": "table", "refId": "tbl_city_snapshot" }
|
|
22864
|
+
]
|
|
22865
|
+
}
|
|
22866
|
+
]
|
|
22867
|
+
},
|
|
22868
|
+
{
|
|
22869
|
+
"id": "row_step_2_actions",
|
|
22870
|
+
"type": "row",
|
|
22871
|
+
"children": [
|
|
22872
|
+
{
|
|
22873
|
+
"id": "col_step_2_back",
|
|
22874
|
+
"type": "col",
|
|
22875
|
+
"responsive": { "xs": 12, "md": 4 },
|
|
22876
|
+
"children": [
|
|
22877
|
+
{ "id": "w_step_2_back", "type": "widget", "widgetKind": "button", "refId": "btn_back_intake" }
|
|
22878
|
+
]
|
|
22879
|
+
},
|
|
22880
|
+
{
|
|
22881
|
+
"id": "col_step_2_continue",
|
|
22882
|
+
"type": "col",
|
|
22883
|
+
"responsive": { "xs": 12, "md": 8 },
|
|
22884
|
+
"children": [
|
|
22885
|
+
{ "id": "w_step_2_continue", "type": "widget", "widgetKind": "button", "refId": "btn_continue_details" }
|
|
22886
|
+
]
|
|
22887
|
+
}
|
|
22888
|
+
]
|
|
22889
|
+
}
|
|
22890
|
+
]
|
|
22891
|
+
}
|
|
22892
|
+
};
|
|
22893
|
+
const JOURNEY_BRANCHING_TEMPLATE_STEP_THREE = {
|
|
22894
|
+
"id": "template-journey-branch-step-3",
|
|
22895
|
+
"version": "1.0.0",
|
|
22896
|
+
"schemaVersion": "1.0.0",
|
|
22897
|
+
"flavor": "form",
|
|
22898
|
+
"title": "Step 3 · Details",
|
|
22899
|
+
"metadata": {
|
|
22900
|
+
"example": true,
|
|
22901
|
+
"scenario": "journey-branching",
|
|
22902
|
+
"page": "details"
|
|
22903
|
+
},
|
|
22904
|
+
"fields": [
|
|
22905
|
+
{
|
|
22906
|
+
"id": "fld_follow_up_date",
|
|
22907
|
+
"widgetId": "core.form:date",
|
|
22908
|
+
"name": "followUpDate",
|
|
22909
|
+
"type": "date",
|
|
22910
|
+
"label": "Follow-up Date"
|
|
22911
|
+
},
|
|
22912
|
+
{
|
|
22913
|
+
"id": "fld_follow_up_time",
|
|
22914
|
+
"widgetId": "core.form:time",
|
|
22915
|
+
"name": "followUpTime",
|
|
22916
|
+
"type": "time",
|
|
22917
|
+
"label": "Follow-up Time"
|
|
22918
|
+
},
|
|
22919
|
+
{
|
|
22920
|
+
"id": "fld_notes",
|
|
22921
|
+
"widgetId": "core.form:text",
|
|
22922
|
+
"name": "notes",
|
|
22923
|
+
"type": "text",
|
|
22924
|
+
"label": "Notes",
|
|
22925
|
+
"placeholder": "Add short notes for this request"
|
|
22926
|
+
},
|
|
22927
|
+
{
|
|
22928
|
+
"id": "fld_summary_currency",
|
|
22929
|
+
"widgetId": "core.form:text",
|
|
22930
|
+
"name": "summaryCurrency",
|
|
22931
|
+
"type": "text",
|
|
22932
|
+
"label": "Currency",
|
|
22933
|
+
"readonly": true,
|
|
22934
|
+
"dataConfig": {
|
|
22935
|
+
"type": "source",
|
|
22936
|
+
"datasourceId": "journey_branch_ds_country_profile",
|
|
22937
|
+
"valueKey": "currency"
|
|
22938
|
+
}
|
|
22939
|
+
},
|
|
22940
|
+
{
|
|
22941
|
+
"id": "fld_summary_timezone",
|
|
22942
|
+
"widgetId": "core.form:text",
|
|
22943
|
+
"name": "summaryTimezone",
|
|
22944
|
+
"type": "text",
|
|
22945
|
+
"label": "Timezone",
|
|
22946
|
+
"readonly": true,
|
|
22947
|
+
"dataConfig": {
|
|
22948
|
+
"type": "source",
|
|
22949
|
+
"datasourceId": "journey_branch_ds_country_profile",
|
|
22950
|
+
"valueKey": "timezone"
|
|
22951
|
+
}
|
|
22952
|
+
},
|
|
22953
|
+
{
|
|
22954
|
+
"id": "btn_back_preferences",
|
|
22955
|
+
"widgetId": "core.form:form-button",
|
|
22956
|
+
"name": "backToPreferences",
|
|
22957
|
+
"type": "form-button",
|
|
22958
|
+
"label": "Back to Preferences",
|
|
22959
|
+
"variant": "secondary",
|
|
22960
|
+
"buttonType": "button",
|
|
22961
|
+
"events": [
|
|
22962
|
+
{
|
|
22963
|
+
"id": "evt_back_to_preferences",
|
|
22964
|
+
"on": "click",
|
|
22965
|
+
"enabled": true,
|
|
22966
|
+
"actions": [
|
|
22967
|
+
{ "type": "navigate", "targetPageId": "page-preferences" }
|
|
22968
|
+
]
|
|
22969
|
+
}
|
|
22970
|
+
]
|
|
22971
|
+
},
|
|
22972
|
+
{
|
|
22973
|
+
"id": "btn_jump_intake",
|
|
22974
|
+
"widgetId": "core.form:form-button",
|
|
22975
|
+
"name": "jumpToIntake",
|
|
22976
|
+
"type": "form-button",
|
|
22977
|
+
"label": "Jump to Intake",
|
|
22978
|
+
"variant": "secondary",
|
|
22979
|
+
"buttonType": "button",
|
|
22980
|
+
"events": [
|
|
22981
|
+
{
|
|
22982
|
+
"id": "evt_jump_to_intake",
|
|
22983
|
+
"on": "click",
|
|
22984
|
+
"enabled": true,
|
|
22985
|
+
"actions": [
|
|
22986
|
+
{ "type": "navigate", "targetPageId": "page-intake" }
|
|
22987
|
+
]
|
|
22988
|
+
}
|
|
22989
|
+
]
|
|
22990
|
+
}
|
|
22991
|
+
],
|
|
22992
|
+
"layout": {
|
|
22993
|
+
"id": "layout_step_3_root",
|
|
22994
|
+
"type": "col",
|
|
22995
|
+
"responsive": { "xs": 12 },
|
|
22996
|
+
"children": [
|
|
22997
|
+
{
|
|
22998
|
+
"id": "row_step_3_inputs",
|
|
22999
|
+
"type": "row",
|
|
23000
|
+
"children": [
|
|
23001
|
+
{
|
|
23002
|
+
"id": "col_step_3_date",
|
|
23003
|
+
"type": "col",
|
|
23004
|
+
"responsive": { "xs": 12, "md": 4 },
|
|
23005
|
+
"children": [
|
|
23006
|
+
{ "id": "w_step_3_date", "type": "widget", "widgetKind": "field", "refId": "fld_follow_up_date" }
|
|
23007
|
+
]
|
|
23008
|
+
},
|
|
23009
|
+
{
|
|
23010
|
+
"id": "col_step_3_time",
|
|
23011
|
+
"type": "col",
|
|
23012
|
+
"responsive": { "xs": 12, "md": 4 },
|
|
23013
|
+
"children": [
|
|
23014
|
+
{ "id": "w_step_3_time", "type": "widget", "widgetKind": "field", "refId": "fld_follow_up_time" }
|
|
23015
|
+
]
|
|
23016
|
+
},
|
|
23017
|
+
{
|
|
23018
|
+
"id": "col_step_3_notes",
|
|
23019
|
+
"type": "col",
|
|
23020
|
+
"responsive": { "xs": 12, "md": 4 },
|
|
23021
|
+
"children": [
|
|
23022
|
+
{ "id": "w_step_3_notes", "type": "widget", "widgetKind": "field", "refId": "fld_notes" }
|
|
23023
|
+
]
|
|
23024
|
+
}
|
|
23025
|
+
]
|
|
23026
|
+
},
|
|
23027
|
+
{
|
|
23028
|
+
"id": "row_step_3_summary",
|
|
23029
|
+
"type": "row",
|
|
23030
|
+
"children": [
|
|
23031
|
+
{
|
|
23032
|
+
"id": "col_step_3_currency",
|
|
23033
|
+
"type": "col",
|
|
23034
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
23035
|
+
"children": [
|
|
23036
|
+
{ "id": "w_step_3_currency", "type": "widget", "widgetKind": "field", "refId": "fld_summary_currency" }
|
|
23037
|
+
]
|
|
23038
|
+
},
|
|
23039
|
+
{
|
|
23040
|
+
"id": "col_step_3_timezone",
|
|
23041
|
+
"type": "col",
|
|
23042
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
23043
|
+
"children": [
|
|
23044
|
+
{ "id": "w_step_3_timezone", "type": "widget", "widgetKind": "field", "refId": "fld_summary_timezone" }
|
|
23045
|
+
]
|
|
23046
|
+
}
|
|
23047
|
+
]
|
|
23048
|
+
},
|
|
23049
|
+
{
|
|
23050
|
+
"id": "row_step_3_actions",
|
|
23051
|
+
"type": "row",
|
|
23052
|
+
"children": [
|
|
23053
|
+
{
|
|
23054
|
+
"id": "col_step_3_back",
|
|
23055
|
+
"type": "col",
|
|
23056
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
23057
|
+
"children": [
|
|
23058
|
+
{ "id": "w_step_3_back", "type": "widget", "widgetKind": "button", "refId": "btn_back_preferences" }
|
|
23059
|
+
]
|
|
23060
|
+
},
|
|
23061
|
+
{
|
|
23062
|
+
"id": "col_step_3_jump",
|
|
23063
|
+
"type": "col",
|
|
23064
|
+
"responsive": { "xs": 12, "md": 6 },
|
|
23065
|
+
"children": [
|
|
23066
|
+
{ "id": "w_step_3_jump", "type": "widget", "widgetKind": "button", "refId": "btn_jump_intake" }
|
|
23067
|
+
]
|
|
23068
|
+
}
|
|
23069
|
+
]
|
|
23070
|
+
}
|
|
23071
|
+
]
|
|
23072
|
+
}
|
|
23073
|
+
};
|
|
23074
|
+
const JOURNEY_BRANCHING_STEP_ONE_SCHEMA = parseTemplateSchema(JOURNEY_BRANCHING_TEMPLATE_STEP_ONE);
|
|
23075
|
+
const JOURNEY_BRANCHING_STEP_TWO_SCHEMA = parseTemplateSchema(JOURNEY_BRANCHING_TEMPLATE_STEP_TWO);
|
|
23076
|
+
const JOURNEY_BRANCHING_STEP_THREE_SCHEMA = parseTemplateSchema(JOURNEY_BRANCHING_TEMPLATE_STEP_THREE);
|
|
23077
|
+
const JOURNEY_BRANCHING_TEMPLATE_PROJECT = {
|
|
23078
|
+
id: 'template-journey-branching',
|
|
23079
|
+
title: 'Journey Branching + Editable Pages',
|
|
23080
|
+
startPageId: 'page-intake',
|
|
23081
|
+
pages: [
|
|
23082
|
+
{
|
|
23083
|
+
id: 'page-intake',
|
|
23084
|
+
name: 'Step 1: Intake + Routing',
|
|
23085
|
+
route: '/journey-intake',
|
|
23086
|
+
schema: JOURNEY_BRANCHING_STEP_ONE_SCHEMA
|
|
23087
|
+
},
|
|
23088
|
+
{
|
|
23089
|
+
id: 'page-preferences',
|
|
23090
|
+
name: 'Step 2: Preferences',
|
|
23091
|
+
route: '/journey-preferences',
|
|
23092
|
+
schema: JOURNEY_BRANCHING_STEP_TWO_SCHEMA
|
|
23093
|
+
},
|
|
23094
|
+
{
|
|
23095
|
+
id: 'page-details',
|
|
23096
|
+
name: 'Step 3: Details',
|
|
23097
|
+
route: '/journey-details',
|
|
23098
|
+
schema: JOURNEY_BRANCHING_STEP_THREE_SCHEMA
|
|
23099
|
+
}
|
|
23100
|
+
],
|
|
23101
|
+
metadata: {
|
|
23102
|
+
example: true,
|
|
23103
|
+
scenario: 'journey-branching'
|
|
23104
|
+
}
|
|
23105
|
+
};
|
|
21591
23106
|
const DEFAULT_TEMPLATE_LIBRARY = [
|
|
21592
23107
|
{
|
|
21593
23108
|
id: 'basic-contact',
|
|
@@ -21616,6 +23131,14 @@ const DEFAULT_TEMPLATE_LIBRARY = [
|
|
|
21616
23131
|
description: 'KYC transfer starter with request-channel routing, client lookup, and conditional beneficiary verification.',
|
|
21617
23132
|
tags: ['operations', 'kyc', 'review', 'dense'],
|
|
21618
23133
|
schema: TRANSACTION_KYC_REVIEW_SCHEMA
|
|
23134
|
+
},
|
|
23135
|
+
{
|
|
23136
|
+
id: 'journey-branching-3-step',
|
|
23137
|
+
name: 'Journey Branching (3 Steps)',
|
|
23138
|
+
description: 'Three-page journey template with datasource events, conditional page navigation, and editable details step.',
|
|
23139
|
+
tags: ['journey', 'events', 'datasource', 'navigation'],
|
|
23140
|
+
schema: JOURNEY_BRANCHING_STEP_ONE_SCHEMA,
|
|
23141
|
+
journey: JOURNEY_BRANCHING_TEMPLATE_PROJECT
|
|
21619
23142
|
}
|
|
21620
23143
|
];
|
|
21621
23144
|
|
|
@@ -21631,6 +23154,7 @@ class EventsWorkspaceComponent {
|
|
|
21631
23154
|
readOnly = input(false);
|
|
21632
23155
|
eventApis = input([]);
|
|
21633
23156
|
eventApiBrowser = input();
|
|
23157
|
+
pages = input([]);
|
|
21634
23158
|
schemaChange = output();
|
|
21635
23159
|
eventsSave = output();
|
|
21636
23160
|
draftSchema = signal(null);
|
|
@@ -21647,6 +23171,20 @@ class EventsWorkspaceComponent {
|
|
|
21647
23171
|
{ label: 'Field', value: 'field' },
|
|
21648
23172
|
{ label: 'Event Payload', value: 'event' }
|
|
21649
23173
|
];
|
|
23174
|
+
conditionOperatorOptions = [
|
|
23175
|
+
{ label: 'Equals', value: 'eq' },
|
|
23176
|
+
{ label: 'Not Equals', value: 'neq' },
|
|
23177
|
+
{ label: 'Greater Than', value: 'gt' },
|
|
23178
|
+
{ label: 'Less Than', value: 'lt' },
|
|
23179
|
+
{ label: 'Greater Or Equals', value: 'gte' },
|
|
23180
|
+
{ label: 'Less Or Equals', value: 'lte' },
|
|
23181
|
+
{ label: 'Contains', value: 'contains' },
|
|
23182
|
+
{ label: 'Starts With', value: 'startsWith' },
|
|
23183
|
+
{ label: 'Ends With', value: 'endsWith' },
|
|
23184
|
+
{ label: 'Is Empty', value: 'empty' },
|
|
23185
|
+
{ label: 'Is Not Empty', value: 'notEmpty' },
|
|
23186
|
+
{ label: 'Is Truthy', value: 'truthy' }
|
|
23187
|
+
];
|
|
21650
23188
|
currentSchema = computed(() => this.draftSchema() ?? this.schema());
|
|
21651
23189
|
fields = computed(() => this.flattenFields(this.currentSchema()));
|
|
21652
23190
|
filteredFields = computed(() => {
|
|
@@ -21755,6 +23293,7 @@ class EventsWorkspaceComponent {
|
|
|
21755
23293
|
return [
|
|
21756
23294
|
{ label: 'Set Value', value: 'setValue' },
|
|
21757
23295
|
{ label: 'Log', value: 'log' },
|
|
23296
|
+
{ label: 'Navigate', value: 'navigate' },
|
|
21758
23297
|
{ label: 'API', value: 'api', disabled: !this.canSelectApiAction(binding, actionIndex) }
|
|
21759
23298
|
];
|
|
21760
23299
|
}
|
|
@@ -21834,6 +23373,14 @@ class EventsWorkspaceComponent {
|
|
|
21834
23373
|
binding.actions[actionIndex] = nextAction;
|
|
21835
23374
|
return;
|
|
21836
23375
|
}
|
|
23376
|
+
if (currentAction.type === 'navigate') {
|
|
23377
|
+
const nextAction = {
|
|
23378
|
+
...currentAction,
|
|
23379
|
+
...patch
|
|
23380
|
+
};
|
|
23381
|
+
binding.actions[actionIndex] = nextAction;
|
|
23382
|
+
return;
|
|
23383
|
+
}
|
|
21837
23384
|
const nextAction = {
|
|
21838
23385
|
...currentAction,
|
|
21839
23386
|
...patch,
|
|
@@ -22039,6 +23586,91 @@ class EventsWorkspaceComponent {
|
|
|
22039
23586
|
asApi(action) {
|
|
22040
23587
|
return action;
|
|
22041
23588
|
}
|
|
23589
|
+
asNavigate(action) {
|
|
23590
|
+
return action;
|
|
23591
|
+
}
|
|
23592
|
+
updateNavigateTarget(bindingIndex, actionIndex, targetPageId) {
|
|
23593
|
+
this.patchAction(bindingIndex, actionIndex, { targetPageId });
|
|
23594
|
+
}
|
|
23595
|
+
hasNavigateCondition(action) {
|
|
23596
|
+
return !!action.when;
|
|
23597
|
+
}
|
|
23598
|
+
toggleNavigateCondition(bindingIndex, actionIndex, enabled) {
|
|
23599
|
+
if (!enabled) {
|
|
23600
|
+
this.updateNavigateConditionGroup(bindingIndex, actionIndex, undefined);
|
|
23601
|
+
return;
|
|
23602
|
+
}
|
|
23603
|
+
this.updateNavigateConditionGroup(bindingIndex, actionIndex, {
|
|
23604
|
+
operator: 'AND',
|
|
23605
|
+
conditions: []
|
|
23606
|
+
});
|
|
23607
|
+
}
|
|
23608
|
+
updateNavigateConditionGroup(bindingIndex, actionIndex, group) {
|
|
23609
|
+
this.patchAction(bindingIndex, actionIndex, { when: group ? this.clone(group) : undefined });
|
|
23610
|
+
}
|
|
23611
|
+
navigateConditionFieldId(action) {
|
|
23612
|
+
const condition = this.firstNavigateCondition(action);
|
|
23613
|
+
return condition?.fieldId ?? '';
|
|
23614
|
+
}
|
|
23615
|
+
navigateConditionOperator(action) {
|
|
23616
|
+
const condition = this.firstNavigateCondition(action);
|
|
23617
|
+
return condition?.operator ?? 'notEmpty';
|
|
23618
|
+
}
|
|
23619
|
+
navigateConditionValue(action) {
|
|
23620
|
+
const condition = this.firstNavigateCondition(action);
|
|
23621
|
+
if (!condition || condition.value === null || condition.value === undefined)
|
|
23622
|
+
return '';
|
|
23623
|
+
return String(condition.value);
|
|
23624
|
+
}
|
|
23625
|
+
updateNavigateConditionField(bindingIndex, actionIndex, fieldId) {
|
|
23626
|
+
if (!fieldId) {
|
|
23627
|
+
this.updateNavigateConditionGroup(bindingIndex, actionIndex, undefined);
|
|
23628
|
+
return;
|
|
23629
|
+
}
|
|
23630
|
+
const action = this.selectedFieldEvents()[bindingIndex]?.actions[actionIndex];
|
|
23631
|
+
const operator = action && action.type === 'navigate'
|
|
23632
|
+
? this.navigateConditionOperator(action)
|
|
23633
|
+
: 'notEmpty';
|
|
23634
|
+
const nextCondition = { fieldId, operator };
|
|
23635
|
+
this.updateNavigateConditionGroup(bindingIndex, actionIndex, this.toNavigateLogicGroup(nextCondition));
|
|
23636
|
+
}
|
|
23637
|
+
updateNavigateConditionOperator(bindingIndex, actionIndex, operator) {
|
|
23638
|
+
const action = this.selectedFieldEvents()[bindingIndex]?.actions[actionIndex];
|
|
23639
|
+
if (!action || action.type !== 'navigate')
|
|
23640
|
+
return;
|
|
23641
|
+
const current = this.firstNavigateCondition(action);
|
|
23642
|
+
if (!current?.fieldId)
|
|
23643
|
+
return;
|
|
23644
|
+
const next = { ...current, operator };
|
|
23645
|
+
if (!this.navigateOperatorNeedsValue(operator)) {
|
|
23646
|
+
delete next.value;
|
|
23647
|
+
}
|
|
23648
|
+
this.updateNavigateConditionGroup(bindingIndex, actionIndex, this.toNavigateLogicGroup(next));
|
|
23649
|
+
}
|
|
23650
|
+
updateNavigateConditionValue(bindingIndex, actionIndex, value) {
|
|
23651
|
+
const action = this.selectedFieldEvents()[bindingIndex]?.actions[actionIndex];
|
|
23652
|
+
if (!action || action.type !== 'navigate')
|
|
23653
|
+
return;
|
|
23654
|
+
const current = this.firstNavigateCondition(action);
|
|
23655
|
+
if (!current?.fieldId)
|
|
23656
|
+
return;
|
|
23657
|
+
const next = {
|
|
23658
|
+
...current,
|
|
23659
|
+
value
|
|
23660
|
+
};
|
|
23661
|
+
this.updateNavigateConditionGroup(bindingIndex, actionIndex, this.toNavigateLogicGroup(next));
|
|
23662
|
+
}
|
|
23663
|
+
navigateOperatorNeedsValue(operator) {
|
|
23664
|
+
return !['empty', 'notEmpty', 'truthy'].includes(operator);
|
|
23665
|
+
}
|
|
23666
|
+
navigateConditionFields() {
|
|
23667
|
+
return this.fields().map(field => ({
|
|
23668
|
+
id: field.id,
|
|
23669
|
+
name: field.name,
|
|
23670
|
+
label: field.label,
|
|
23671
|
+
type: field.type
|
|
23672
|
+
}));
|
|
23673
|
+
}
|
|
22042
23674
|
trackFieldById(_, field) {
|
|
22043
23675
|
return field.id;
|
|
22044
23676
|
}
|
|
@@ -22070,6 +23702,22 @@ class EventsWorkspaceComponent {
|
|
|
22070
23702
|
const selectedId = this.selectedFieldId();
|
|
22071
23703
|
return this.fields().filter(field => field.id !== selectedId);
|
|
22072
23704
|
}
|
|
23705
|
+
firstNavigateCondition(action) {
|
|
23706
|
+
const when = action.when;
|
|
23707
|
+
if (!when?.conditions?.length)
|
|
23708
|
+
return null;
|
|
23709
|
+
const first = when.conditions[0];
|
|
23710
|
+
return this.isLogicCondition(first) ? first : null;
|
|
23711
|
+
}
|
|
23712
|
+
isLogicCondition(value) {
|
|
23713
|
+
return 'fieldId' in value;
|
|
23714
|
+
}
|
|
23715
|
+
toNavigateLogicGroup(condition) {
|
|
23716
|
+
return {
|
|
23717
|
+
operator: 'AND',
|
|
23718
|
+
conditions: [condition]
|
|
23719
|
+
};
|
|
23720
|
+
}
|
|
22073
23721
|
updateSelectedEvents(mutator) {
|
|
22074
23722
|
if (this.readOnly())
|
|
22075
23723
|
return;
|
|
@@ -22104,6 +23752,13 @@ class EventsWorkspaceComponent {
|
|
|
22104
23752
|
outputTransformScript: 'return output;'
|
|
22105
23753
|
};
|
|
22106
23754
|
}
|
|
23755
|
+
if (type === 'navigate') {
|
|
23756
|
+
return {
|
|
23757
|
+
type: 'navigate',
|
|
23758
|
+
targetPageId: '',
|
|
23759
|
+
when: undefined
|
|
23760
|
+
};
|
|
23761
|
+
}
|
|
22107
23762
|
return {
|
|
22108
23763
|
type: 'log',
|
|
22109
23764
|
message: DEFAULT_LOG_ACTION_MESSAGE
|
|
@@ -22458,7 +24113,7 @@ class EventsWorkspaceComponent {
|
|
|
22458
24113
|
return `evt_ds_${v4().replace(/-/g, '')}`;
|
|
22459
24114
|
}
|
|
22460
24115
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EventsWorkspaceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
22461
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: EventsWorkspaceComponent, isStandalone: true, selector: "app-events-workspace", inputs: { schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: true, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, eventApis: { classPropertyName: "eventApis", publicName: "eventApis", isSignal: true, isRequired: false, transformFunction: null }, eventApiBrowser: { classPropertyName: "eventApiBrowser", publicName: "eventApiBrowser", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { schemaChange: "schemaChange", eventsSave: "eventsSave" }, host: { classAttribute: "fd-events-workspace-host block h-full w-full" }, ngImport: i0, template: `
|
|
24116
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: EventsWorkspaceComponent, isStandalone: true, selector: "app-events-workspace", inputs: { schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: true, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, eventApis: { classPropertyName: "eventApis", publicName: "eventApis", isSignal: true, isRequired: false, transformFunction: null }, eventApiBrowser: { classPropertyName: "eventApiBrowser", publicName: "eventApiBrowser", isSignal: true, isRequired: false, transformFunction: null }, pages: { classPropertyName: "pages", publicName: "pages", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { schemaChange: "schemaChange", eventsSave: "eventsSave" }, host: { classAttribute: "fd-events-workspace-host block h-full w-full" }, ngImport: i0, template: `
|
|
22462
24117
|
<div class="fd-events-workspace flex h-full w-full overflow-hidden bg-white font-sans text-sm text-gray-700" data-fd="events-workspace">
|
|
22463
24118
|
<aside class="fd-events-fields w-72 shrink-0 border-r border-gray-200 bg-gray-50 flex flex-col" data-fd-region="fields">
|
|
22464
24119
|
<div class="px-4 py-3 border-b border-gray-200 bg-white">
|
|
@@ -22637,6 +24292,43 @@ class EventsWorkspaceComponent {
|
|
|
22637
24292
|
placeholder="Enter log message">
|
|
22638
24293
|
</ng-container>
|
|
22639
24294
|
|
|
24295
|
+
<ng-container *ngIf="action.type === 'navigate'">
|
|
24296
|
+
<div>
|
|
24297
|
+
<label class="mb-1 block text-[11px] font-medium text-gray-600">Target Page</label>
|
|
24298
|
+
<select
|
|
24299
|
+
class="h-8 w-full rounded-md border border-gray-300 px-2 text-xs focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
|
24300
|
+
[disabled]="readOnly()"
|
|
24301
|
+
[ngModel]="asNavigate(action).targetPageId"
|
|
24302
|
+
(ngModelChange)="updateNavigateTarget(bindingIndex, actionIndex, $event)">
|
|
24303
|
+
<option value="">Select page</option>
|
|
24304
|
+
<option *ngFor="let page of pages()" [value]="page.id">{{ page.name }}</option>
|
|
24305
|
+
</select>
|
|
24306
|
+
</div>
|
|
24307
|
+
|
|
24308
|
+
<div class="rounded-md border border-gray-200 bg-white p-3">
|
|
24309
|
+
<label class="inline-flex items-center gap-2 text-[11px] font-medium text-gray-600">
|
|
24310
|
+
<input
|
|
24311
|
+
type="checkbox"
|
|
24312
|
+
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
24313
|
+
[disabled]="readOnly()"
|
|
24314
|
+
[ngModel]="hasNavigateCondition(asNavigate(action))"
|
|
24315
|
+
(ngModelChange)="toggleNavigateCondition(bindingIndex, actionIndex, $event)">
|
|
24316
|
+
<span>Use condition</span>
|
|
24317
|
+
</label>
|
|
24318
|
+
<p class="mt-1 text-[10px] text-gray-500">
|
|
24319
|
+
Reuses the same rules query builder used by widget rules.
|
|
24320
|
+
</p>
|
|
24321
|
+
|
|
24322
|
+
<div *ngIf="hasNavigateCondition(asNavigate(action))" class="mt-3">
|
|
24323
|
+
<app-query-builder
|
|
24324
|
+
[group]="asNavigate(action).when!"
|
|
24325
|
+
[allFields]="navigateConditionFields()"
|
|
24326
|
+
(groupChange)="updateNavigateConditionGroup(bindingIndex, actionIndex, $event)">
|
|
24327
|
+
</app-query-builder>
|
|
24328
|
+
</div>
|
|
24329
|
+
</div>
|
|
24330
|
+
</ng-container>
|
|
24331
|
+
|
|
22640
24332
|
<ng-container *ngIf="action.type === 'api'">
|
|
22641
24333
|
<label class="mb-1 block text-[11px] font-medium text-gray-600">API</label>
|
|
22642
24334
|
<div class="rounded-md border border-gray-200 bg-white">
|
|
@@ -22791,7 +24483,7 @@ class EventsWorkspaceComponent {
|
|
|
22791
24483
|
</ng-template>
|
|
22792
24484
|
</section>
|
|
22793
24485
|
</div>
|
|
22794
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
24486
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: QueryBuilderComponent, selector: "app-query-builder", inputs: ["group", "allFields", "level"], outputs: ["groupChange", "remove"] }] });
|
|
22795
24487
|
}
|
|
22796
24488
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EventsWorkspaceComponent, decorators: [{
|
|
22797
24489
|
type: Component,
|
|
@@ -22801,7 +24493,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
22801
24493
|
host: {
|
|
22802
24494
|
class: 'fd-events-workspace-host block h-full w-full'
|
|
22803
24495
|
},
|
|
22804
|
-
imports: [CommonModule, FormsModule],
|
|
24496
|
+
imports: [CommonModule, FormsModule, QueryBuilderComponent],
|
|
22805
24497
|
template: `
|
|
22806
24498
|
<div class="fd-events-workspace flex h-full w-full overflow-hidden bg-white font-sans text-sm text-gray-700" data-fd="events-workspace">
|
|
22807
24499
|
<aside class="fd-events-fields w-72 shrink-0 border-r border-gray-200 bg-gray-50 flex flex-col" data-fd-region="fields">
|
|
@@ -22981,6 +24673,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
22981
24673
|
placeholder="Enter log message">
|
|
22982
24674
|
</ng-container>
|
|
22983
24675
|
|
|
24676
|
+
<ng-container *ngIf="action.type === 'navigate'">
|
|
24677
|
+
<div>
|
|
24678
|
+
<label class="mb-1 block text-[11px] font-medium text-gray-600">Target Page</label>
|
|
24679
|
+
<select
|
|
24680
|
+
class="h-8 w-full rounded-md border border-gray-300 px-2 text-xs focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
|
24681
|
+
[disabled]="readOnly()"
|
|
24682
|
+
[ngModel]="asNavigate(action).targetPageId"
|
|
24683
|
+
(ngModelChange)="updateNavigateTarget(bindingIndex, actionIndex, $event)">
|
|
24684
|
+
<option value="">Select page</option>
|
|
24685
|
+
<option *ngFor="let page of pages()" [value]="page.id">{{ page.name }}</option>
|
|
24686
|
+
</select>
|
|
24687
|
+
</div>
|
|
24688
|
+
|
|
24689
|
+
<div class="rounded-md border border-gray-200 bg-white p-3">
|
|
24690
|
+
<label class="inline-flex items-center gap-2 text-[11px] font-medium text-gray-600">
|
|
24691
|
+
<input
|
|
24692
|
+
type="checkbox"
|
|
24693
|
+
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
24694
|
+
[disabled]="readOnly()"
|
|
24695
|
+
[ngModel]="hasNavigateCondition(asNavigate(action))"
|
|
24696
|
+
(ngModelChange)="toggleNavigateCondition(bindingIndex, actionIndex, $event)">
|
|
24697
|
+
<span>Use condition</span>
|
|
24698
|
+
</label>
|
|
24699
|
+
<p class="mt-1 text-[10px] text-gray-500">
|
|
24700
|
+
Reuses the same rules query builder used by widget rules.
|
|
24701
|
+
</p>
|
|
24702
|
+
|
|
24703
|
+
<div *ngIf="hasNavigateCondition(asNavigate(action))" class="mt-3">
|
|
24704
|
+
<app-query-builder
|
|
24705
|
+
[group]="asNavigate(action).when!"
|
|
24706
|
+
[allFields]="navigateConditionFields()"
|
|
24707
|
+
(groupChange)="updateNavigateConditionGroup(bindingIndex, actionIndex, $event)">
|
|
24708
|
+
</app-query-builder>
|
|
24709
|
+
</div>
|
|
24710
|
+
</div>
|
|
24711
|
+
</ng-container>
|
|
24712
|
+
|
|
22984
24713
|
<ng-container *ngIf="action.type === 'api'">
|
|
22985
24714
|
<label class="mb-1 block text-[11px] font-medium text-gray-600">API</label>
|
|
22986
24715
|
<div class="rounded-md border border-gray-200 bg-white">
|
|
@@ -23139,6 +24868,158 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
23139
24868
|
}]
|
|
23140
24869
|
}], ctorParameters: () => [] });
|
|
23141
24870
|
|
|
24871
|
+
class FormJourneyStateService {
|
|
24872
|
+
documentSignal = signal(normalizeToJourney(createEmptySchema('form')));
|
|
24873
|
+
sourceWasPlainSchema = signal(true);
|
|
24874
|
+
document = computed(() => this.documentSignal());
|
|
24875
|
+
pages = computed(() => this.documentSignal().pages);
|
|
24876
|
+
activePageId = signal(this.documentSignal().startPageId);
|
|
24877
|
+
activePage = computed(() => this.pages().find(page => page.id === this.activePageId()) ?? null);
|
|
24878
|
+
canRemovePage = computed(() => this.pages().length > 1);
|
|
24879
|
+
isJourneyMode = computed(() => this.pages().length > 1);
|
|
24880
|
+
setDocument(input) {
|
|
24881
|
+
const fromSchema = !this.isJourneyInput(input);
|
|
24882
|
+
const normalized = normalizeToJourney(input);
|
|
24883
|
+
this.documentSignal.set(normalized);
|
|
24884
|
+
this.sourceWasPlainSchema.set(fromSchema);
|
|
24885
|
+
this.activePageId.set(normalized.startPageId);
|
|
24886
|
+
}
|
|
24887
|
+
setActivePage(id) {
|
|
24888
|
+
if (this.pages().some(page => page.id === id)) {
|
|
24889
|
+
this.activePageId.set(id);
|
|
24890
|
+
}
|
|
24891
|
+
}
|
|
24892
|
+
addPage() {
|
|
24893
|
+
const current = this.documentSignal();
|
|
24894
|
+
const name = this.nextPageName();
|
|
24895
|
+
const route = this.ensureUniqueRoute(`/${name.toLowerCase().replace(/\s+/g, '-')}`);
|
|
24896
|
+
const page = createFormJourneyPage({
|
|
24897
|
+
name,
|
|
24898
|
+
route,
|
|
24899
|
+
schema: createEmptySchema('form', { title: name })
|
|
24900
|
+
});
|
|
24901
|
+
this.documentSignal.set({
|
|
24902
|
+
...current,
|
|
24903
|
+
pages: [...current.pages, page]
|
|
24904
|
+
});
|
|
24905
|
+
this.activePageId.set(page.id);
|
|
24906
|
+
return page;
|
|
24907
|
+
}
|
|
24908
|
+
removePage(id) {
|
|
24909
|
+
if (!this.canRemovePage())
|
|
24910
|
+
return;
|
|
24911
|
+
const current = this.documentSignal();
|
|
24912
|
+
const pages = current.pages.filter(page => page.id !== id);
|
|
24913
|
+
if (pages.length === current.pages.length || pages.length === 0)
|
|
24914
|
+
return;
|
|
24915
|
+
const startPageId = pages.some(page => page.id === current.startPageId)
|
|
24916
|
+
? current.startPageId
|
|
24917
|
+
: pages[0].id;
|
|
24918
|
+
this.documentSignal.set({
|
|
24919
|
+
...current,
|
|
24920
|
+
pages,
|
|
24921
|
+
startPageId
|
|
24922
|
+
});
|
|
24923
|
+
if (this.activePageId() === id) {
|
|
24924
|
+
this.activePageId.set(startPageId);
|
|
24925
|
+
}
|
|
24926
|
+
}
|
|
24927
|
+
renamePage(id, name) {
|
|
24928
|
+
const trimmed = name.trim();
|
|
24929
|
+
if (!trimmed)
|
|
24930
|
+
return;
|
|
24931
|
+
const current = this.documentSignal();
|
|
24932
|
+
const pages = current.pages.map(page => {
|
|
24933
|
+
if (page.id !== id)
|
|
24934
|
+
return page;
|
|
24935
|
+
return {
|
|
24936
|
+
...page,
|
|
24937
|
+
name: trimmed,
|
|
24938
|
+
schema: {
|
|
24939
|
+
...page.schema,
|
|
24940
|
+
title: trimmed
|
|
24941
|
+
}
|
|
24942
|
+
};
|
|
24943
|
+
});
|
|
24944
|
+
this.documentSignal.set({ ...current, pages });
|
|
24945
|
+
}
|
|
24946
|
+
updateRoute(id, route) {
|
|
24947
|
+
const current = this.documentSignal();
|
|
24948
|
+
const pages = current.pages.map(page => {
|
|
24949
|
+
if (page.id !== id)
|
|
24950
|
+
return page;
|
|
24951
|
+
return {
|
|
24952
|
+
...page,
|
|
24953
|
+
route: this.ensureUniqueRoute(route, id)
|
|
24954
|
+
};
|
|
24955
|
+
});
|
|
24956
|
+
this.documentSignal.set({ ...current, pages });
|
|
24957
|
+
}
|
|
24958
|
+
updateActivePageSchema(schema) {
|
|
24959
|
+
const activeId = this.activePageId();
|
|
24960
|
+
if (!activeId)
|
|
24961
|
+
return;
|
|
24962
|
+
this.updatePageSchema(activeId, schema);
|
|
24963
|
+
}
|
|
24964
|
+
updatePageSchema(id, schema) {
|
|
24965
|
+
const current = this.documentSignal();
|
|
24966
|
+
const pages = current.pages.map(page => {
|
|
24967
|
+
if (page.id !== id)
|
|
24968
|
+
return page;
|
|
24969
|
+
return {
|
|
24970
|
+
...page,
|
|
24971
|
+
schema: { ...schema }
|
|
24972
|
+
};
|
|
24973
|
+
});
|
|
24974
|
+
this.documentSignal.set({ ...current, pages });
|
|
24975
|
+
}
|
|
24976
|
+
compatibleOutput() {
|
|
24977
|
+
const current = this.documentSignal();
|
|
24978
|
+
if (current.pages.length === 1 && this.sourceWasPlainSchema()) {
|
|
24979
|
+
return unwrapSinglePageJourney(current);
|
|
24980
|
+
}
|
|
24981
|
+
return current;
|
|
24982
|
+
}
|
|
24983
|
+
isJourneyInput(input) {
|
|
24984
|
+
return 'pages' in input;
|
|
24985
|
+
}
|
|
24986
|
+
nextPageName() {
|
|
24987
|
+
const names = new Set(this.pages().map(page => page.name.toLowerCase()));
|
|
24988
|
+
let i = this.pages().length + 1;
|
|
24989
|
+
while (names.has(`step ${i}`.toLowerCase())) {
|
|
24990
|
+
i += 1;
|
|
24991
|
+
}
|
|
24992
|
+
return `Step ${i}`;
|
|
24993
|
+
}
|
|
24994
|
+
ensureUniqueRoute(route, excludeId) {
|
|
24995
|
+
const normalized = this.normalizeRoute(route);
|
|
24996
|
+
const existing = new Set(this.pages()
|
|
24997
|
+
.filter(page => page.id !== excludeId)
|
|
24998
|
+
.map(page => page.route));
|
|
24999
|
+
if (!existing.has(normalized))
|
|
25000
|
+
return normalized;
|
|
25001
|
+
const base = normalized.replace(/-\d+$/, '');
|
|
25002
|
+
let index = 2;
|
|
25003
|
+
let candidate = `${base}-${index}`;
|
|
25004
|
+
while (existing.has(candidate)) {
|
|
25005
|
+
index += 1;
|
|
25006
|
+
candidate = `${base}-${index}`;
|
|
25007
|
+
}
|
|
25008
|
+
return candidate;
|
|
25009
|
+
}
|
|
25010
|
+
normalizeRoute(route) {
|
|
25011
|
+
const trimmed = route.trim().toLowerCase();
|
|
25012
|
+
if (!trimmed)
|
|
25013
|
+
return '/step';
|
|
25014
|
+
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
25015
|
+
}
|
|
25016
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormJourneyStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
25017
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormJourneyStateService });
|
|
25018
|
+
}
|
|
25019
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormJourneyStateService, decorators: [{
|
|
25020
|
+
type: Injectable
|
|
25021
|
+
}] });
|
|
25022
|
+
|
|
23142
25023
|
function parseExternalDsProperties(value) {
|
|
23143
25024
|
if (!value)
|
|
23144
25025
|
return {};
|
|
@@ -23185,9 +25066,11 @@ function normalizeDataSourceType(type) {
|
|
|
23185
25066
|
}
|
|
23186
25067
|
class FormDesignerShellComponent {
|
|
23187
25068
|
state = inject(DesignerStateService);
|
|
25069
|
+
journeyState = inject(FormJourneyStateService);
|
|
23188
25070
|
aiAvailable = inject(AI_BACKEND_CLIENT, { optional: true }) !== null;
|
|
23189
|
-
|
|
25071
|
+
aiFeatureState = inject(FormDesignerAiFeatureStateService);
|
|
23190
25072
|
schema;
|
|
25073
|
+
journey;
|
|
23191
25074
|
schemaMetadata;
|
|
23192
25075
|
flavor = 'form';
|
|
23193
25076
|
flavors = ['form', 'email'];
|
|
@@ -23210,6 +25093,9 @@ class FormDesignerShellComponent {
|
|
|
23210
25093
|
save = new EventEmitter();
|
|
23211
25094
|
push = new EventEmitter();
|
|
23212
25095
|
eventsSave = new EventEmitter();
|
|
25096
|
+
saveDocument = new EventEmitter();
|
|
25097
|
+
pushDocument = new EventEmitter();
|
|
25098
|
+
editDocument = new EventEmitter();
|
|
23213
25099
|
catalog = inject(DataCatalog, { optional: true });
|
|
23214
25100
|
managedSourceIds = new Set();
|
|
23215
25101
|
managedEventSourceIds = new Set();
|
|
@@ -23220,6 +25106,18 @@ class FormDesignerShellComponent {
|
|
|
23220
25106
|
selectedTemplateId = null;
|
|
23221
25107
|
pendingTemplate = null;
|
|
23222
25108
|
lastSavedSchemaSnapshot = this.serializeSchema(this.state.schema());
|
|
25109
|
+
designerPages = computed(() => this.journeyState.pages().map(page => ({
|
|
25110
|
+
id: page.id,
|
|
25111
|
+
name: page.name,
|
|
25112
|
+
route: page.route
|
|
25113
|
+
})));
|
|
25114
|
+
journeySyncEnabled = signal(false);
|
|
25115
|
+
schemaSync = effect(() => {
|
|
25116
|
+
if (!this.journeySyncEnabled())
|
|
25117
|
+
return;
|
|
25118
|
+
const schema = this.state.schema();
|
|
25119
|
+
untracked(() => this.journeyState.updateActivePageSchema(schema));
|
|
25120
|
+
});
|
|
23223
25121
|
get engine() {
|
|
23224
25122
|
return new FormEngine(this.state.schema());
|
|
23225
25123
|
}
|
|
@@ -23229,12 +25127,16 @@ class FormDesignerShellComponent {
|
|
|
23229
25127
|
get selectedTemplate() {
|
|
23230
25128
|
return this.filteredTemplates.find(template => template.id === this.selectedTemplateId) ?? null;
|
|
23231
25129
|
}
|
|
25130
|
+
constructor() {
|
|
25131
|
+
this.journeyState.setDocument(this.state.schema());
|
|
25132
|
+
this.journeySyncEnabled.set(true);
|
|
25133
|
+
}
|
|
23232
25134
|
get resolvedHeaderLabel() {
|
|
23233
25135
|
const explicitLabel = this.headerLabel?.trim();
|
|
23234
25136
|
if (explicitLabel) {
|
|
23235
25137
|
return explicitLabel;
|
|
23236
25138
|
}
|
|
23237
|
-
const activeSchema = this.getResolvedExternalSchema() ?? this.state.schema();
|
|
25139
|
+
const activeSchema = this.journeyState.activePage()?.schema ?? this.getResolvedExternalSchema() ?? this.state.schema();
|
|
23238
25140
|
const schemaTitle = activeSchema?.title?.trim() || 'Untitled Form';
|
|
23239
25141
|
const schemaVersion = activeSchema?.version?.trim();
|
|
23240
25142
|
return schemaVersion ? `${schemaTitle} [${schemaVersion}]` : schemaTitle;
|
|
@@ -23246,19 +25148,14 @@ class FormDesignerShellComponent {
|
|
|
23246
25148
|
if (changes['isReadOnly']) {
|
|
23247
25149
|
this.state.setIsReadOnly(this.isReadOnly);
|
|
23248
25150
|
}
|
|
23249
|
-
if (changes['schema'] || changes['schemaMetadata']) {
|
|
23250
|
-
|
|
23251
|
-
if (resolvedSchema) {
|
|
23252
|
-
this.state.updateSchema(resolvedSchema);
|
|
23253
|
-
this.syncEventDataSources(resolvedSchema);
|
|
23254
|
-
this.lastSavedSchemaSnapshot = this.serializeSchema(resolvedSchema);
|
|
23255
|
-
}
|
|
25151
|
+
if (changes['schema'] || changes['journey'] || changes['schemaMetadata']) {
|
|
25152
|
+
this.loadExternalDocument();
|
|
23256
25153
|
}
|
|
23257
25154
|
if (changes['dataSources']) {
|
|
23258
25155
|
this.syncDataSources();
|
|
23259
25156
|
}
|
|
23260
25157
|
if (changes['eventApis']) {
|
|
23261
|
-
this.
|
|
25158
|
+
this.aiFeatureState.setEventApis(this.eventApis ?? []);
|
|
23262
25159
|
}
|
|
23263
25160
|
}
|
|
23264
25161
|
syncDataSources() {
|
|
@@ -23412,6 +25309,37 @@ class FormDesignerShellComponent {
|
|
|
23412
25309
|
closeAiWorkspace() {
|
|
23413
25310
|
this.activeWorkspace = 'designer';
|
|
23414
25311
|
}
|
|
25312
|
+
addPage() {
|
|
25313
|
+
this.persistActivePage();
|
|
25314
|
+
this.journeyState.addPage();
|
|
25315
|
+
this.loadActivePage();
|
|
25316
|
+
}
|
|
25317
|
+
selectPage(id) {
|
|
25318
|
+
if (this.journeyState.activePageId() === id)
|
|
25319
|
+
return;
|
|
25320
|
+
this.persistActivePage();
|
|
25321
|
+
this.journeyState.setActivePage(id);
|
|
25322
|
+
this.loadActivePage();
|
|
25323
|
+
}
|
|
25324
|
+
removePage(id) {
|
|
25325
|
+
if (!this.journeyState.canRemovePage())
|
|
25326
|
+
return;
|
|
25327
|
+
this.persistActivePage();
|
|
25328
|
+
this.journeyState.removePage(id);
|
|
25329
|
+
this.loadActivePage();
|
|
25330
|
+
}
|
|
25331
|
+
renamePage(id, name) {
|
|
25332
|
+
this.journeyState.renamePage(id, name);
|
|
25333
|
+
if (this.journeyState.activePageId() === id) {
|
|
25334
|
+
const current = this.state.schema();
|
|
25335
|
+
if (current.title !== name) {
|
|
25336
|
+
this.state.updateSchema({ ...current, title: name });
|
|
25337
|
+
}
|
|
25338
|
+
}
|
|
25339
|
+
}
|
|
25340
|
+
updatePageRoute(id, route) {
|
|
25341
|
+
this.journeyState.updateRoute(id, route);
|
|
25342
|
+
}
|
|
23415
25343
|
onEventsSchemaChange(schema) {
|
|
23416
25344
|
if (this.state.isReadOnly())
|
|
23417
25345
|
return;
|
|
@@ -23449,16 +25377,24 @@ class FormDesignerShellComponent {
|
|
|
23449
25377
|
this.pendingTemplate = null;
|
|
23450
25378
|
}
|
|
23451
25379
|
onEdit() {
|
|
25380
|
+
this.persistActivePage();
|
|
25381
|
+
const output = this.journeyState.compatibleOutput();
|
|
23452
25382
|
this.state.setIsReadOnly(false);
|
|
23453
|
-
this.edit.emit(
|
|
25383
|
+
this.edit.emit(output);
|
|
25384
|
+
this.editDocument.emit(output);
|
|
23454
25385
|
}
|
|
23455
25386
|
onSave() {
|
|
25387
|
+
this.persistActivePage();
|
|
23456
25388
|
const schema = this.state.schema();
|
|
25389
|
+
const output = this.journeyState.compatibleOutput();
|
|
23457
25390
|
this.lastSavedSchemaSnapshot = this.serializeSchema(schema);
|
|
23458
|
-
this.save.emit(
|
|
25391
|
+
this.save.emit(output);
|
|
25392
|
+
this.saveDocument.emit(output);
|
|
23459
25393
|
}
|
|
23460
25394
|
onPush() {
|
|
25395
|
+
this.persistActivePage();
|
|
23461
25396
|
const schema = this.state.schema();
|
|
25397
|
+
const output = this.journeyState.compatibleOutput();
|
|
23462
25398
|
if (this.hasUnsavedChanges(schema)) {
|
|
23463
25399
|
const confirmed = typeof confirm === 'function'
|
|
23464
25400
|
? confirm('You have unsaved changes. Push without saving may publish the previously saved form. Continue?')
|
|
@@ -23466,7 +25402,8 @@ class FormDesignerShellComponent {
|
|
|
23466
25402
|
if (!confirmed)
|
|
23467
25403
|
return;
|
|
23468
25404
|
}
|
|
23469
|
-
this.push.emit(
|
|
25405
|
+
this.push.emit(output);
|
|
25406
|
+
this.pushDocument.emit(output);
|
|
23470
25407
|
}
|
|
23471
25408
|
trackByTemplateId(_index, template) {
|
|
23472
25409
|
return template.id;
|
|
@@ -23484,6 +25421,18 @@ class FormDesignerShellComponent {
|
|
|
23484
25421
|
return JSON.stringify(schema);
|
|
23485
25422
|
}
|
|
23486
25423
|
applyTemplate(template) {
|
|
25424
|
+
if (template.journey) {
|
|
25425
|
+
const journey = this.parseTemplateJourney(template.journey);
|
|
25426
|
+
this.journeyState.setDocument(journey);
|
|
25427
|
+
this.loadActivePage();
|
|
25428
|
+
this.selectedTemplateId = template.id;
|
|
25429
|
+
this.closeLibrary();
|
|
25430
|
+
const activeSchema = this.journeyState.activePage()?.schema;
|
|
25431
|
+
if (activeSchema?.flavor && activeSchema.flavor !== this.flavor) {
|
|
25432
|
+
this.switchFlavor(activeSchema.flavor);
|
|
25433
|
+
}
|
|
25434
|
+
return;
|
|
25435
|
+
}
|
|
23487
25436
|
const schema = parseSchema(JSON.stringify(template.schema));
|
|
23488
25437
|
schema.id = this.createSchemaId();
|
|
23489
25438
|
schema.flavor = schema.flavor ?? this.flavor;
|
|
@@ -23496,6 +25445,20 @@ class FormDesignerShellComponent {
|
|
|
23496
25445
|
this.switchFlavor(resolvedSchema.flavor);
|
|
23497
25446
|
}
|
|
23498
25447
|
}
|
|
25448
|
+
parseTemplateJourney(template) {
|
|
25449
|
+
const pages = template.pages.map(page => ({
|
|
25450
|
+
...page,
|
|
25451
|
+
schema: parseSchema(JSON.stringify(page.schema))
|
|
25452
|
+
}));
|
|
25453
|
+
const startPageId = pages.some(page => page.id === template.startPageId)
|
|
25454
|
+
? template.startPageId
|
|
25455
|
+
: pages[0]?.id ?? '';
|
|
25456
|
+
return {
|
|
25457
|
+
...template,
|
|
25458
|
+
pages,
|
|
25459
|
+
startPageId
|
|
25460
|
+
};
|
|
25461
|
+
}
|
|
23499
25462
|
syncTemplateSelection() {
|
|
23500
25463
|
const templates = this.filteredTemplates;
|
|
23501
25464
|
if (!templates.length) {
|
|
@@ -23512,7 +25475,31 @@ class FormDesignerShellComponent {
|
|
|
23512
25475
|
}
|
|
23513
25476
|
return `schema-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
23514
25477
|
}
|
|
23515
|
-
|
|
25478
|
+
loadExternalDocument() {
|
|
25479
|
+
const resolved = this.getResolvedExternalDocument();
|
|
25480
|
+
if (!resolved)
|
|
25481
|
+
return;
|
|
25482
|
+
this.journeySyncEnabled.set(false);
|
|
25483
|
+
this.journeyState.setDocument(resolved);
|
|
25484
|
+
this.loadActivePage();
|
|
25485
|
+
this.lastSavedSchemaSnapshot = this.serializeSchema(this.state.schema());
|
|
25486
|
+
this.journeySyncEnabled.set(true);
|
|
25487
|
+
}
|
|
25488
|
+
loadActivePage() {
|
|
25489
|
+
const active = this.journeyState.activePage();
|
|
25490
|
+
if (!active)
|
|
25491
|
+
return;
|
|
25492
|
+
this.state.updateSchema(active.schema);
|
|
25493
|
+
this.syncEventDataSources(active.schema);
|
|
25494
|
+
}
|
|
25495
|
+
persistActivePage() {
|
|
25496
|
+
const currentSchema = this.state.schema();
|
|
25497
|
+
this.journeyState.updateActivePageSchema(currentSchema);
|
|
25498
|
+
}
|
|
25499
|
+
getResolvedExternalDocument() {
|
|
25500
|
+
if (this.journey) {
|
|
25501
|
+
return this.journey;
|
|
25502
|
+
}
|
|
23516
25503
|
if (this.schema) {
|
|
23517
25504
|
return this.applySchemaMetadata(this.schema);
|
|
23518
25505
|
}
|
|
@@ -23521,6 +25508,17 @@ class FormDesignerShellComponent {
|
|
|
23521
25508
|
}
|
|
23522
25509
|
return undefined;
|
|
23523
25510
|
}
|
|
25511
|
+
getResolvedExternalSchema() {
|
|
25512
|
+
const external = this.getResolvedExternalDocument();
|
|
25513
|
+
if (!external)
|
|
25514
|
+
return undefined;
|
|
25515
|
+
if (isFormJourneyProject(external)) {
|
|
25516
|
+
return external.pages.find(page => page.id === external.startPageId)?.schema
|
|
25517
|
+
?? external.pages[0]?.schema
|
|
25518
|
+
?? undefined;
|
|
25519
|
+
}
|
|
25520
|
+
return external;
|
|
25521
|
+
}
|
|
23524
25522
|
applySchemaMetadata(schema) {
|
|
23525
25523
|
const metadata = this.schemaMetadata;
|
|
23526
25524
|
if (!metadata) {
|
|
@@ -23548,7 +25546,7 @@ class FormDesignerShellComponent {
|
|
|
23548
25546
|
};
|
|
23549
25547
|
}
|
|
23550
25548
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormDesignerShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23551
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormDesignerShellComponent, isStandalone: true, selector: "app-form-designer-shell", inputs: { schema: "schema", schemaMetadata: "schemaMetadata", flavor: "flavor", flavors: "flavors", templates: "templates", headerLabel: "headerLabel", enableTemplateLibrary: "enableTemplateLibrary", enableGlobalDataManager: "enableGlobalDataManager", enableAiAssistant: "enableAiAssistant", showEditButton: "showEditButton", showSaveButton: "showSaveButton", showPushButton: "showPushButton", showEmailPreview: "showEmailPreview", isReadOnly: "isReadOnly", dataSources: "dataSources", eventApis: "eventApis", eventApiBrowser: "eventApiBrowser", eventApiExecutor: "eventApiExecutor" }, outputs: { flavorChange: "flavorChange", edit: "edit", save: "save", push: "push", eventsSave: "eventsSave" }, host: { classAttribute: "fd-shell-host block h-full w-full" }, usesOnChanges: true, ngImport: i0, template: `
|
|
25549
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormDesignerShellComponent, isStandalone: true, selector: "app-form-designer-shell", inputs: { schema: "schema", journey: "journey", schemaMetadata: "schemaMetadata", flavor: "flavor", flavors: "flavors", templates: "templates", headerLabel: "headerLabel", enableTemplateLibrary: "enableTemplateLibrary", enableGlobalDataManager: "enableGlobalDataManager", enableAiAssistant: "enableAiAssistant", showEditButton: "showEditButton", showSaveButton: "showSaveButton", showPushButton: "showPushButton", showEmailPreview: "showEmailPreview", isReadOnly: "isReadOnly", dataSources: "dataSources", eventApis: "eventApis", eventApiBrowser: "eventApiBrowser", eventApiExecutor: "eventApiExecutor" }, outputs: { flavorChange: "flavorChange", edit: "edit", save: "save", push: "push", eventsSave: "eventsSave", saveDocument: "saveDocument", pushDocument: "pushDocument", editDocument: "editDocument" }, host: { classAttribute: "fd-shell-host block h-full w-full" }, providers: [FormJourneyStateService, ...provideFormDesignerAngaiFeature()], usesOnChanges: true, ngImport: i0, template: `
|
|
23552
25550
|
<div
|
|
23553
25551
|
class="fd-shell flex flex-col h-screen bg-white font-sans"
|
|
23554
25552
|
data-fd="shell"
|
|
@@ -23669,6 +25667,7 @@ class FormDesignerShellComponent {
|
|
|
23669
25667
|
data-fd-slot="events-workspace"
|
|
23670
25668
|
*ngIf="activeWorkspace === 'events'; else designerWorkspace"
|
|
23671
25669
|
[schema]="state.schema()"
|
|
25670
|
+
[pages]="designerPages()"
|
|
23672
25671
|
[readOnly]="state.isReadOnly()"
|
|
23673
25672
|
[eventApis]="eventApis"
|
|
23674
25673
|
[eventApiBrowser]="eventApiBrowser"
|
|
@@ -23683,7 +25682,15 @@ class FormDesignerShellComponent {
|
|
|
23683
25682
|
[flavor]="flavor"
|
|
23684
25683
|
[mode]="state.isReadOnly() ? 'view' : 'edit'"
|
|
23685
25684
|
[eventApis]="eventApis"
|
|
23686
|
-
[eventApiExecutor]="eventApiExecutor"
|
|
25685
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
25686
|
+
[pages]="designerPages()"
|
|
25687
|
+
[activePageId]="journeyState.activePageId()"
|
|
25688
|
+
[canRemovePage]="journeyState.canRemovePage()"
|
|
25689
|
+
(pageAdd)="addPage()"
|
|
25690
|
+
(pageSelect)="selectPage($event)"
|
|
25691
|
+
(pageRemove)="removePage($event)"
|
|
25692
|
+
(pageRename)="renamePage($event.id, $event.name)"
|
|
25693
|
+
(pageRouteChange)="updatePageRoute($event.id, $event.route)">
|
|
23687
25694
|
</app-json-form-designer>
|
|
23688
25695
|
</ng-template>
|
|
23689
25696
|
|
|
@@ -23823,13 +25830,13 @@ class FormDesignerShellComponent {
|
|
|
23823
25830
|
</div>
|
|
23824
25831
|
</section>
|
|
23825
25832
|
</div>
|
|
23826
|
-
`, isInline: true, styles: ["@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.animate-slide-in-right{animation:slideInRight .3s cubic-bezier(.16,1,.3,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.TitleCasePipe, name: "titlecase" }, { kind: "component", type: JsonFormDesignerComponent, selector: "app-json-form-designer", inputs: ["flavor", "mode", "eventApis", "eventApiExecutor"] }, { kind: "component", type: EventsWorkspaceComponent, selector: "app-events-workspace", inputs: ["schema", "readOnly", "eventApis", "eventApiBrowser"], outputs: ["schemaChange", "eventsSave"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "component", type: EmailRendererComponent, selector: "app-email-renderer", inputs: ["schema", "engine"] }, { kind: "component", type: GlobalDataManagerComponent, selector: "app-global-data-manager", outputs: ["close"] }, { kind: "component", type: AiChatDrawerComponent, selector: "app-ai-chat-drawer", outputs: ["close", "expand"] }, { kind: "component", type: AiWorkspaceComponent, selector: "app-ai-workspace", outputs: ["close"] }] });
|
|
25833
|
+
`, isInline: true, styles: ["@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.animate-slide-in-right{animation:slideInRight .3s cubic-bezier(.16,1,.3,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.TitleCasePipe, name: "titlecase" }, { kind: "component", type: JsonFormDesignerComponent, selector: "app-json-form-designer", inputs: ["flavor", "mode", "eventApis", "eventApiExecutor", "pages", "activePageId", "canRemovePage"], outputs: ["pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange"] }, { kind: "component", type: EventsWorkspaceComponent, selector: "app-events-workspace", inputs: ["schema", "readOnly", "eventApis", "eventApiBrowser", "pages"], outputs: ["schemaChange", "eventsSave"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "initialFieldLabels", "mode", "device", "showLayoutGuides", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "navigateToPage", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "component", type: EmailRendererComponent, selector: "app-email-renderer", inputs: ["schema", "engine"] }, { kind: "component", type: GlobalDataManagerComponent, selector: "app-global-data-manager", outputs: ["close"] }, { kind: "component", type: AiChatDrawerComponent, selector: "app-ai-chat-drawer", outputs: ["close", "expand"] }, { kind: "component", type: AiWorkspaceComponent, selector: "app-ai-workspace", outputs: ["close"] }] });
|
|
23827
25834
|
}
|
|
23828
25835
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormDesignerShellComponent, decorators: [{
|
|
23829
25836
|
type: Component,
|
|
23830
25837
|
args: [{ selector: 'app-form-designer-shell', standalone: true, host: {
|
|
23831
25838
|
class: 'fd-shell-host block h-full w-full'
|
|
23832
|
-
}, imports: [
|
|
25839
|
+
}, providers: [FormJourneyStateService, ...provideFormDesignerAngaiFeature()], imports: [
|
|
23833
25840
|
CommonModule,
|
|
23834
25841
|
JsonFormDesignerComponent,
|
|
23835
25842
|
EventsWorkspaceComponent,
|
|
@@ -23959,6 +25966,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
23959
25966
|
data-fd-slot="events-workspace"
|
|
23960
25967
|
*ngIf="activeWorkspace === 'events'; else designerWorkspace"
|
|
23961
25968
|
[schema]="state.schema()"
|
|
25969
|
+
[pages]="designerPages()"
|
|
23962
25970
|
[readOnly]="state.isReadOnly()"
|
|
23963
25971
|
[eventApis]="eventApis"
|
|
23964
25972
|
[eventApiBrowser]="eventApiBrowser"
|
|
@@ -23973,7 +25981,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
23973
25981
|
[flavor]="flavor"
|
|
23974
25982
|
[mode]="state.isReadOnly() ? 'view' : 'edit'"
|
|
23975
25983
|
[eventApis]="eventApis"
|
|
23976
|
-
[eventApiExecutor]="eventApiExecutor"
|
|
25984
|
+
[eventApiExecutor]="eventApiExecutor"
|
|
25985
|
+
[pages]="designerPages()"
|
|
25986
|
+
[activePageId]="journeyState.activePageId()"
|
|
25987
|
+
[canRemovePage]="journeyState.canRemovePage()"
|
|
25988
|
+
(pageAdd)="addPage()"
|
|
25989
|
+
(pageSelect)="selectPage($event)"
|
|
25990
|
+
(pageRemove)="removePage($event)"
|
|
25991
|
+
(pageRename)="renamePage($event.id, $event.name)"
|
|
25992
|
+
(pageRouteChange)="updatePageRoute($event.id, $event.route)">
|
|
23977
25993
|
</app-json-form-designer>
|
|
23978
25994
|
</ng-template>
|
|
23979
25995
|
|
|
@@ -24114,7 +26130,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
24114
26130
|
</section>
|
|
24115
26131
|
</div>
|
|
24116
26132
|
`, styles: ["@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.animate-slide-in-right{animation:slideInRight .3s cubic-bezier(.16,1,.3,1)}\n"] }]
|
|
24117
|
-
}], propDecorators: { schema: [{
|
|
26133
|
+
}], ctorParameters: () => [], propDecorators: { schema: [{
|
|
26134
|
+
type: Input
|
|
26135
|
+
}], journey: [{
|
|
24118
26136
|
type: Input
|
|
24119
26137
|
}], schemaMetadata: [{
|
|
24120
26138
|
type: Input
|
|
@@ -24160,6 +26178,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
24160
26178
|
type: Output
|
|
24161
26179
|
}], eventsSave: [{
|
|
24162
26180
|
type: Output
|
|
26181
|
+
}], saveDocument: [{
|
|
26182
|
+
type: Output
|
|
26183
|
+
}], pushDocument: [{
|
|
26184
|
+
type: Output
|
|
26185
|
+
}], editDocument: [{
|
|
26186
|
+
type: Output
|
|
24163
26187
|
}] } });
|
|
24164
26188
|
|
|
24165
26189
|
class EventsPanelComponent {
|
|
@@ -27171,7 +29195,7 @@ class WebsiteDesignerShellComponent {
|
|
|
27171
29195
|
|
|
27172
29196
|
<input type="file" #projectFileInput accept=".json" (change)="onProjectFileSelected($event)" class="hidden">
|
|
27173
29197
|
</div>
|
|
27174
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview", inputs: ["eventApis", "eventApiExecutor", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
29198
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview", inputs: ["eventApis", "eventApiExecutor", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "pages", "activePageId"], outputs: ["pageSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
27175
29199
|
}
|
|
27176
29200
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: WebsiteDesignerShellComponent, decorators: [{
|
|
27177
29201
|
type: Component,
|
|
@@ -29060,7 +31084,7 @@ class WebsitePreviewShellComponent {
|
|
|
29060
31084
|
}
|
|
29061
31085
|
</main>
|
|
29062
31086
|
</div>
|
|
29063
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
|
|
31087
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "initialFieldLabels", "mode", "device", "showLayoutGuides", "breakpoint", "eventLogger", "eventApis", "eventApiExecutor", "navigateToPage", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
|
|
29064
31088
|
}
|
|
29065
31089
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: WebsitePreviewShellComponent, decorators: [{
|
|
29066
31090
|
type: Component,
|
|
@@ -29701,7 +31725,7 @@ function getTextControlClass(options) {
|
|
|
29701
31725
|
: 'border-transparent focus:border-transparent focus:ring-0'
|
|
29702
31726
|
: options?.invalid
|
|
29703
31727
|
? TEXT_CONTROL_INVALID_CLASS
|
|
29704
|
-
: TEXT_CONTROL_VALID_CLASS, 'h-full min-h-0', multiline ? 'min-h-[96px] py-2 leading-6 resize-y' : compact ? 'min-h-[
|
|
31728
|
+
: TEXT_CONTROL_VALID_CLASS, 'h-full min-h-0', multiline ? 'min-h-[96px] py-2 leading-6 resize-y' : compact ? 'min-h-[30px] py-0.5' : 'min-h-[30px] py-0.5', options?.leadingInset && 'pl-10', options?.trailingInset && 'pr-10');
|
|
29705
31729
|
}
|
|
29706
31730
|
function getChoiceControlClass(options) {
|
|
29707
31731
|
return joinClasses('mt-0.5 h-[18px] w-[18px] border-2 bg-[#FFFFFF] text-[#7FB2FF] transition focus:ring-2 focus:ring-[#7FB2FF] focus:ring-offset-0', options?.radio ? 'rounded-full' : 'rounded-[2px]', options?.invalid ? 'border-red-500 focus:ring-red-200' : 'border-[#3F8CFF] checked:border-[#7FB2FF]');
|
|
@@ -29791,6 +31815,9 @@ class TextFieldWidgetComponent {
|
|
|
29791
31815
|
isTextarea() {
|
|
29792
31816
|
return this.config?.type === 'textarea';
|
|
29793
31817
|
}
|
|
31818
|
+
isColorField() {
|
|
31819
|
+
return this.config?.type === 'color';
|
|
31820
|
+
}
|
|
29794
31821
|
getControlClass(multiline = false) {
|
|
29795
31822
|
return getTextControlClass({
|
|
29796
31823
|
invalid: !!this.error,
|
|
@@ -29896,6 +31923,23 @@ class TextFieldWidgetComponent {
|
|
|
29896
31923
|
onMouseLeave() {
|
|
29897
31924
|
this.isControlHovered = false;
|
|
29898
31925
|
}
|
|
31926
|
+
getColorPickerValue() {
|
|
31927
|
+
const currentValue = this.control.value;
|
|
31928
|
+
if (typeof currentValue === 'string' && currentValue.trim().length > 0) {
|
|
31929
|
+
return currentValue;
|
|
31930
|
+
}
|
|
31931
|
+
const defaultValue = this.config?.defaultValue;
|
|
31932
|
+
if (typeof defaultValue === 'string' && defaultValue.trim().length > 0) {
|
|
31933
|
+
return defaultValue;
|
|
31934
|
+
}
|
|
31935
|
+
return '#000000';
|
|
31936
|
+
}
|
|
31937
|
+
onColorPickerChange(color) {
|
|
31938
|
+
if (this.control.pristine) {
|
|
31939
|
+
this.control.markAsDirty();
|
|
31940
|
+
}
|
|
31941
|
+
this.control.setValue(color);
|
|
31942
|
+
}
|
|
29899
31943
|
ngOnDestroy() {
|
|
29900
31944
|
// Cleanup handled by takeUntilDestroyed
|
|
29901
31945
|
}
|
|
@@ -30074,6 +32118,31 @@ class TextFieldWidgetComponent {
|
|
|
30074
32118
|
[class]="getControlClass(true)"
|
|
30075
32119
|
[ngStyle]="getControlStyles()"
|
|
30076
32120
|
data-fd="field-control"></textarea>
|
|
32121
|
+
} @else if (isColorField()) {
|
|
32122
|
+
<input
|
|
32123
|
+
[id]="fieldId"
|
|
32124
|
+
type="text"
|
|
32125
|
+
[placeholder]="config.placeholder || ''"
|
|
32126
|
+
[formControl]="control"
|
|
32127
|
+
(click)="onClick()"
|
|
32128
|
+
(focus)="onFocus()"
|
|
32129
|
+
(blur)="onBlur()"
|
|
32130
|
+
(mouseenter)="onMouseEnter()"
|
|
32131
|
+
(mouseleave)="onMouseLeave()"
|
|
32132
|
+
[readonly]="config.readonly"
|
|
32133
|
+
[attr.aria-required]="required"
|
|
32134
|
+
[attr.aria-invalid]="!!error"
|
|
32135
|
+
[attr.aria-describedby]="getAriaDescribedBy()"
|
|
32136
|
+
[attr.aria-label]="getAccessibleLabel()"
|
|
32137
|
+
[class]="getControlClass()"
|
|
32138
|
+
[ngStyle]="getControlStyles()"
|
|
32139
|
+
data-fd="field-control"
|
|
32140
|
+
[colorPicker]="getColorPickerValue()"
|
|
32141
|
+
[cpAlphaChannel]="'disabled'"
|
|
32142
|
+
[cpOutputFormat]="'hex'"
|
|
32143
|
+
[cpFallbackColor]="'#000000'"
|
|
32144
|
+
[cpDisabled]="config.readonly || !enabled"
|
|
32145
|
+
(colorPickerChange)="onColorPickerChange($event)">
|
|
30077
32146
|
} @else {
|
|
30078
32147
|
<input
|
|
30079
32148
|
[id]="fieldId"
|
|
@@ -30107,14 +32176,14 @@ class TextFieldWidgetComponent {
|
|
|
30107
32176
|
<p [id]="helpTextId" [class]="fieldHelpClass" data-fd="field-help">{{ config.helpText }}</p>
|
|
30108
32177
|
}
|
|
30109
32178
|
</div>
|
|
30110
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
|
|
32179
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: ColorPickerDirective, selector: "[colorPicker]", inputs: ["colorPicker", "cpWidth", "cpHeight", "cpToggle", "cpDisabled", "cpIgnoredElements", "cpFallbackColor", "cpColorMode", "cpCmykEnabled", "cpOutputFormat", "cpAlphaChannel", "cpDisableInput", "cpDialogDisplay", "cpSaveClickOutside", "cpCloseClickOutside", "cpUseRootViewContainer", "cpPosition", "cpPositionOffset", "cpPositionRelativeToArrow", "cpOKButton", "cpOKButtonText", "cpOKButtonClass", "cpCancelButton", "cpCancelButtonText", "cpCancelButtonClass", "cpEyeDropper", "cpPresetLabel", "cpPresetColors", "cpPresetColorsClass", "cpMaxPresetColorsLength", "cpPresetEmptyMessage", "cpPresetEmptyMessageClass", "cpAddColorButton", "cpAddColorButtonText", "cpAddColorButtonClass", "cpRemoveColorButtonClass", "cpArrowPosition", "cpExtraTemplate"], outputs: ["cpInputChange", "cpToggleChange", "cpSliderChange", "cpSliderDragEnd", "cpSliderDragStart", "colorPickerOpen", "colorPickerClose", "colorPickerCancel", "colorPickerSelect", "colorPickerChange", "cpCmykColorChange", "cpPresetColorsChange"], exportAs: ["ngxColorPicker"] }] });
|
|
30111
32180
|
}
|
|
30112
32181
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TextFieldWidgetComponent, decorators: [{
|
|
30113
32182
|
type: Component,
|
|
30114
32183
|
args: [{
|
|
30115
32184
|
selector: 'app-text-field-widget',
|
|
30116
32185
|
standalone: true,
|
|
30117
|
-
imports: [CommonModule, ReactiveFormsModule],
|
|
32186
|
+
imports: [CommonModule, ReactiveFormsModule, ColorPickerDirective],
|
|
30118
32187
|
template: `
|
|
30119
32188
|
<div [class]="fieldContainerClass"
|
|
30120
32189
|
[class.hidden]="!visible"
|
|
@@ -30153,6 +32222,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
30153
32222
|
[class]="getControlClass(true)"
|
|
30154
32223
|
[ngStyle]="getControlStyles()"
|
|
30155
32224
|
data-fd="field-control"></textarea>
|
|
32225
|
+
} @else if (isColorField()) {
|
|
32226
|
+
<input
|
|
32227
|
+
[id]="fieldId"
|
|
32228
|
+
type="text"
|
|
32229
|
+
[placeholder]="config.placeholder || ''"
|
|
32230
|
+
[formControl]="control"
|
|
32231
|
+
(click)="onClick()"
|
|
32232
|
+
(focus)="onFocus()"
|
|
32233
|
+
(blur)="onBlur()"
|
|
32234
|
+
(mouseenter)="onMouseEnter()"
|
|
32235
|
+
(mouseleave)="onMouseLeave()"
|
|
32236
|
+
[readonly]="config.readonly"
|
|
32237
|
+
[attr.aria-required]="required"
|
|
32238
|
+
[attr.aria-invalid]="!!error"
|
|
32239
|
+
[attr.aria-describedby]="getAriaDescribedBy()"
|
|
32240
|
+
[attr.aria-label]="getAccessibleLabel()"
|
|
32241
|
+
[class]="getControlClass()"
|
|
32242
|
+
[ngStyle]="getControlStyles()"
|
|
32243
|
+
data-fd="field-control"
|
|
32244
|
+
[colorPicker]="getColorPickerValue()"
|
|
32245
|
+
[cpAlphaChannel]="'disabled'"
|
|
32246
|
+
[cpOutputFormat]="'hex'"
|
|
32247
|
+
[cpFallbackColor]="'#000000'"
|
|
32248
|
+
[cpDisabled]="config.readonly || !enabled"
|
|
32249
|
+
(colorPickerChange)="onColorPickerChange($event)">
|
|
30156
32250
|
} @else {
|
|
30157
32251
|
<input
|
|
30158
32252
|
[id]="fieldId"
|
|
@@ -30606,6 +32700,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
30606
32700
|
args: ['fileInput']
|
|
30607
32701
|
}] } });
|
|
30608
32702
|
|
|
32703
|
+
function resolveOptionFieldLabel(value, options, existingLabel) {
|
|
32704
|
+
if (value === undefined || value === null || value === '') {
|
|
32705
|
+
return undefined;
|
|
32706
|
+
}
|
|
32707
|
+
if (Array.isArray(value)) {
|
|
32708
|
+
if (value.length === 0) {
|
|
32709
|
+
return undefined;
|
|
32710
|
+
}
|
|
32711
|
+
const labels = value.map((entry, index) => resolveOptionLabel(entry, options, getExistingLabelEntry(existingLabel, index)));
|
|
32712
|
+
return labels.some(label => label !== undefined)
|
|
32713
|
+
? labels.map((label, index) => label ?? String(value[index] ?? ''))
|
|
32714
|
+
: undefined;
|
|
32715
|
+
}
|
|
32716
|
+
return resolveOptionLabel(value, options, typeof existingLabel === 'string' ? existingLabel : undefined);
|
|
32717
|
+
}
|
|
32718
|
+
function buildFallbackOptions(value, label) {
|
|
32719
|
+
if (value === undefined || value === null || value === '') {
|
|
32720
|
+
return [];
|
|
32721
|
+
}
|
|
32722
|
+
if (Array.isArray(value)) {
|
|
32723
|
+
return value
|
|
32724
|
+
.filter(entry => entry !== undefined && entry !== null && String(entry).length > 0)
|
|
32725
|
+
.map((entry, index) => ({
|
|
32726
|
+
label: getExistingLabelEntry(label, index) ?? String(entry),
|
|
32727
|
+
value: toOptionValue(entry)
|
|
32728
|
+
}));
|
|
32729
|
+
}
|
|
32730
|
+
return [{
|
|
32731
|
+
label: typeof label === 'string' && label.length > 0 ? label : String(value),
|
|
32732
|
+
value: toOptionValue(value)
|
|
32733
|
+
}];
|
|
32734
|
+
}
|
|
32735
|
+
function resolveOptionLabel(value, options, existingLabel) {
|
|
32736
|
+
const match = options.find(option => Object.is(option.value, value) || String(option.value) === String(value));
|
|
32737
|
+
if (match?.label) {
|
|
32738
|
+
return match.label;
|
|
32739
|
+
}
|
|
32740
|
+
return existingLabel;
|
|
32741
|
+
}
|
|
32742
|
+
function getExistingLabelEntry(label, index) {
|
|
32743
|
+
if (Array.isArray(label)) {
|
|
32744
|
+
const entry = label[index];
|
|
32745
|
+
return typeof entry === 'string' && entry.length > 0 ? entry : undefined;
|
|
32746
|
+
}
|
|
32747
|
+
if (typeof label === 'string' && index === 0 && label.length > 0) {
|
|
32748
|
+
return label;
|
|
32749
|
+
}
|
|
32750
|
+
return undefined;
|
|
32751
|
+
}
|
|
32752
|
+
function toOptionValue(value) {
|
|
32753
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
32754
|
+
return value;
|
|
32755
|
+
}
|
|
32756
|
+
return String(value ?? '');
|
|
32757
|
+
}
|
|
32758
|
+
|
|
30609
32759
|
const SELECT_CONTROL_STYLE_KEYS = [
|
|
30610
32760
|
'height',
|
|
30611
32761
|
'minHeight',
|
|
@@ -30723,6 +32873,7 @@ class SelectWidgetComponent {
|
|
|
30723
32873
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
30724
32874
|
.subscribe(val => {
|
|
30725
32875
|
if (this.engine) {
|
|
32876
|
+
this.syncStoredFieldLabel(val);
|
|
30726
32877
|
this.engine.setValue(this.config.name, val);
|
|
30727
32878
|
this.runtimeFieldDataAccessRegistry.invalidateFieldAndDescendants(this.engine, this.config.id);
|
|
30728
32879
|
this.engine.emitUiEvent({ fieldId: this.config.id, fieldName: this.config.name, type: 'change', value: val });
|
|
@@ -30734,13 +32885,24 @@ class SelectWidgetComponent {
|
|
|
30734
32885
|
this.syncEnabledState();
|
|
30735
32886
|
this.runtimeManagedField = this.runtimeFieldDataAccessRegistry.hasFieldAccess(this.config, this.engine);
|
|
30736
32887
|
if (!this.runtimeManagedField) {
|
|
30737
|
-
|
|
32888
|
+
if (this.areApiCallsSuppressed() && this.hasSelectedValue()) {
|
|
32889
|
+
this.options = this.withSelectedValueFallbackOptions([]);
|
|
32890
|
+
}
|
|
32891
|
+
else {
|
|
32892
|
+
void this.loadOptions(this.currentSearchTerm);
|
|
32893
|
+
}
|
|
30738
32894
|
this.runtimeOptionsLoaded = true;
|
|
30739
32895
|
}
|
|
30740
32896
|
else if (this.hasSelectedValue()) {
|
|
30741
|
-
|
|
30742
|
-
this.
|
|
30743
|
-
|
|
32897
|
+
if (this.areApiCallsSuppressed()) {
|
|
32898
|
+
this.options = this.withSelectedValueFallbackOptions([]);
|
|
32899
|
+
this.runtimeOptionsLoaded = true;
|
|
32900
|
+
}
|
|
32901
|
+
else {
|
|
32902
|
+
void this.loadOptions(this.currentSearchTerm).then(() => {
|
|
32903
|
+
this.runtimeOptionsLoaded = !this.loadError;
|
|
32904
|
+
});
|
|
32905
|
+
}
|
|
30744
32906
|
}
|
|
30745
32907
|
const dependencyIds = this.getDependencyFieldIds();
|
|
30746
32908
|
if (this.engine) {
|
|
@@ -30750,6 +32912,10 @@ class SelectWidgetComponent {
|
|
|
30750
32912
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
30751
32913
|
.subscribe(values => {
|
|
30752
32914
|
this.syncEnabledState();
|
|
32915
|
+
if (this.areApiCallsSuppressed()) {
|
|
32916
|
+
this.options = this.withSelectedValueFallbackOptions(this.options);
|
|
32917
|
+
this.cdr.markForCheck();
|
|
32918
|
+
}
|
|
30753
32919
|
if (dependencyIds.length === 0)
|
|
30754
32920
|
return;
|
|
30755
32921
|
const schema = this.engine.getSchema();
|
|
@@ -30974,7 +33140,8 @@ class SelectWidgetComponent {
|
|
|
30974
33140
|
opts = await this.dataProvider.getOptions(this.config, this.engine);
|
|
30975
33141
|
}
|
|
30976
33142
|
if (this.requestId === reqId) {
|
|
30977
|
-
this.options = opts;
|
|
33143
|
+
this.options = this.withSelectedValueFallbackOptions(opts);
|
|
33144
|
+
this.syncStoredFieldLabel(this.control.value);
|
|
30978
33145
|
this.loading = false;
|
|
30979
33146
|
this.loadError = null;
|
|
30980
33147
|
this.cdr.markForCheck();
|
|
@@ -30985,7 +33152,7 @@ class SelectWidgetComponent {
|
|
|
30985
33152
|
this.loading = false;
|
|
30986
33153
|
this.loadError = 'Failed to load options.';
|
|
30987
33154
|
if (!isSearch) {
|
|
30988
|
-
this.options = this.config.staticOptions || [];
|
|
33155
|
+
this.options = this.withSelectedValueFallbackOptions(this.config.staticOptions || []);
|
|
30989
33156
|
}
|
|
30990
33157
|
this.cdr.markForCheck();
|
|
30991
33158
|
}
|
|
@@ -31005,6 +33172,11 @@ class SelectWidgetComponent {
|
|
|
31005
33172
|
return;
|
|
31006
33173
|
if (this.runtimeOptionsLoaded && this.options.length > 0)
|
|
31007
33174
|
return;
|
|
33175
|
+
if (this.areApiCallsSuppressed()) {
|
|
33176
|
+
this.options = this.withSelectedValueFallbackOptions(this.options);
|
|
33177
|
+
this.runtimeOptionsLoaded = true;
|
|
33178
|
+
return;
|
|
33179
|
+
}
|
|
31008
33180
|
await this.loadOptions(this.currentSearchTerm);
|
|
31009
33181
|
if (!this.loadError) {
|
|
31010
33182
|
this.runtimeOptionsLoaded = true;
|
|
@@ -31034,14 +33206,7 @@ class SelectWidgetComponent {
|
|
|
31034
33206
|
return changed;
|
|
31035
33207
|
}
|
|
31036
33208
|
hasSelectedValue() {
|
|
31037
|
-
|
|
31038
|
-
if (value === undefined || value === null)
|
|
31039
|
-
return false;
|
|
31040
|
-
if (typeof value === 'string')
|
|
31041
|
-
return value.length > 0;
|
|
31042
|
-
if (Array.isArray(value))
|
|
31043
|
-
return value.length > 0;
|
|
31044
|
-
return true;
|
|
33209
|
+
return this.hasMeaningfulValue(this.resolveSelectedValueForFallback());
|
|
31045
33210
|
}
|
|
31046
33211
|
handleConfigChange() {
|
|
31047
33212
|
this.syncEnabledState();
|
|
@@ -31051,6 +33216,10 @@ class SelectWidgetComponent {
|
|
|
31051
33216
|
this.loadError = null;
|
|
31052
33217
|
this.currentSearchTerm = '';
|
|
31053
33218
|
if (!this.runtimeManagedField) {
|
|
33219
|
+
if (this.areApiCallsSuppressed() && this.hasSelectedValue()) {
|
|
33220
|
+
this.options = this.withSelectedValueFallbackOptions([]);
|
|
33221
|
+
return;
|
|
33222
|
+
}
|
|
31054
33223
|
void this.loadOptions(this.currentSearchTerm);
|
|
31055
33224
|
return;
|
|
31056
33225
|
}
|
|
@@ -31140,6 +33309,72 @@ class SelectWidgetComponent {
|
|
|
31140
33309
|
}
|
|
31141
33310
|
return fallback;
|
|
31142
33311
|
}
|
|
33312
|
+
areApiCallsSuppressed() {
|
|
33313
|
+
return areEngineApiCallsSuppressed(this.engine);
|
|
33314
|
+
}
|
|
33315
|
+
withSelectedValueFallbackOptions(options) {
|
|
33316
|
+
const selected = this.getSelectedFallbackOptions();
|
|
33317
|
+
if (selected.length === 0) {
|
|
33318
|
+
return options;
|
|
33319
|
+
}
|
|
33320
|
+
const merged = [...options];
|
|
33321
|
+
for (const option of selected) {
|
|
33322
|
+
if (this.hasOptionValue(merged, option.value))
|
|
33323
|
+
continue;
|
|
33324
|
+
merged.unshift(option);
|
|
33325
|
+
}
|
|
33326
|
+
return merged;
|
|
33327
|
+
}
|
|
33328
|
+
getSelectedFallbackOptions() {
|
|
33329
|
+
const rawValue = this.resolveSelectedValueForFallback();
|
|
33330
|
+
if (!this.hasMeaningfulValue(rawValue)) {
|
|
33331
|
+
return [];
|
|
33332
|
+
}
|
|
33333
|
+
return buildFallbackOptions(rawValue, this.getStoredFieldLabel());
|
|
33334
|
+
}
|
|
33335
|
+
hasOptionValue(options, value) {
|
|
33336
|
+
return options.some(option => Object.is(option.value, value) || String(option.value) === String(value));
|
|
33337
|
+
}
|
|
33338
|
+
resolveSelectedValueForFallback() {
|
|
33339
|
+
const controlValue = this.control.value;
|
|
33340
|
+
if (this.hasMeaningfulValue(controlValue)) {
|
|
33341
|
+
return controlValue;
|
|
33342
|
+
}
|
|
33343
|
+
if (!this.engine
|
|
33344
|
+
|| !this.config?.name
|
|
33345
|
+
|| typeof this.engine.getValue !== 'function') {
|
|
33346
|
+
return controlValue;
|
|
33347
|
+
}
|
|
33348
|
+
return this.engine.getValue(this.config.name);
|
|
33349
|
+
}
|
|
33350
|
+
hasMeaningfulValue(value) {
|
|
33351
|
+
if (value === undefined || value === null)
|
|
33352
|
+
return false;
|
|
33353
|
+
if (typeof value === 'string')
|
|
33354
|
+
return value.length > 0;
|
|
33355
|
+
if (Array.isArray(value))
|
|
33356
|
+
return value.length > 0;
|
|
33357
|
+
return true;
|
|
33358
|
+
}
|
|
33359
|
+
syncStoredFieldLabel(value) {
|
|
33360
|
+
if (!this.engine || !this.config?.name) {
|
|
33361
|
+
return;
|
|
33362
|
+
}
|
|
33363
|
+
const label = resolveOptionFieldLabel(value, this.options, this.getStoredFieldLabel());
|
|
33364
|
+
this.setStoredFieldLabel(label);
|
|
33365
|
+
}
|
|
33366
|
+
getStoredFieldLabel() {
|
|
33367
|
+
if (!this.engine || typeof this.engine.getFieldLabel !== 'function') {
|
|
33368
|
+
return undefined;
|
|
33369
|
+
}
|
|
33370
|
+
return this.engine.getFieldLabel(this.config.name);
|
|
33371
|
+
}
|
|
33372
|
+
setStoredFieldLabel(label) {
|
|
33373
|
+
if (!this.engine || typeof this.engine.setFieldLabel !== 'function') {
|
|
33374
|
+
return;
|
|
33375
|
+
}
|
|
33376
|
+
this.engine.setFieldLabel(this.config.name, label);
|
|
33377
|
+
}
|
|
31143
33378
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SelectWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
31144
33379
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SelectWidgetComponent, isStandalone: true, selector: "app-select-widget", inputs: { config: "config", engine: "engine", control: "control" }, viewQueries: [{ propertyName: "ngSelectComponent", first: true, predicate: NgSelectComponent, descendants: true }], ngImport: i0, template: `
|
|
31145
33380
|
<div [class]="fieldContainerClass"
|
|
@@ -31217,7 +33452,7 @@ class SelectWidgetComponent {
|
|
|
31217
33452
|
<p [id]="helpTextId" [class]="fieldHelpClass" data-fd="field-help">{{ config.helpText }}</p>
|
|
31218
33453
|
}
|
|
31219
33454
|
</div>
|
|
31220
|
-
`, isInline: true, styles: [":host ::ng-deep ng-select.fd-select{display:block;min-height:0;color:var(--fd-select-text-color, #1C2431)}.fd-select-composite{display:flex;width:100%;min-width:0}:host ::ng-deep ng-select.fd-select .ng-select-container{height:var(--fd-select-height, 100%);min-height:var(--fd-select-min-height,
|
|
33455
|
+
`, isInline: true, styles: [":host ::ng-deep ng-select.fd-select{display:block;min-height:0;color:var(--fd-select-text-color, #1C2431)}.fd-select-composite{display:flex;width:100%;min-width:0}:host ::ng-deep ng-select.fd-select .ng-select-container{height:var(--fd-select-height, 100%);min-height:var(--fd-select-min-height, 30px);border-style:var(--fd-select-border-style, solid);border-width:var(--fd-select-border-width, 1.5px);border-color:var(--fd-select-border-color, #3F8CFF);border-top-style:var(--fd-select-border-top-style, var(--fd-select-border-style, solid));border-right-style:var(--fd-select-border-right-style, var(--fd-select-border-style, solid));border-bottom-style:var(--fd-select-border-bottom-style, var(--fd-select-border-style, solid));border-left-style:var(--fd-select-border-left-style, var(--fd-select-border-style, solid));border-top-width:var(--fd-select-border-top-width, var(--fd-select-border-width, 1.5px));border-right-width:var(--fd-select-border-right-width, var(--fd-select-border-width, 1.5px));border-bottom-width:var(--fd-select-border-bottom-width, var(--fd-select-border-width, 1.5px));border-left-width:var(--fd-select-border-left-width, var(--fd-select-border-width, 1.5px));border-top-color:var(--fd-select-border-top-color, var(--fd-select-border-color, #3F8CFF));border-right-color:var(--fd-select-border-right-color, var(--fd-select-border-color, #3F8CFF));border-bottom-color:var(--fd-select-border-bottom-color, var(--fd-select-border-color, #3F8CFF));border-left-color:var(--fd-select-border-left-color, var(--fd-select-border-color, #3F8CFF));border-radius:var(--fd-select-border-radius, 4px);border-top-left-radius:var(--fd-select-border-top-left-radius, var(--fd-select-border-radius, 4px));border-top-right-radius:var(--fd-select-border-top-right-radius, var(--fd-select-border-radius, 4px));border-bottom-right-radius:var(--fd-select-border-bottom-right-radius, var(--fd-select-border-radius, 4px));border-bottom-left-radius:var(--fd-select-border-bottom-left-radius, var(--fd-select-border-radius, 4px));background:var(--fd-select-background-color, #FFFFFF);box-shadow:var(--fd-select-box-shadow, none);transition:border-color .2s ease,box-shadow .2s ease}:host ::ng-deep ng-select.fd-select:hover .ng-select-container{border-color:var(--fd-select-hover-border-color, var(--fd-select-border-color, #3F8CFF))}:host ::ng-deep ng-select.fd-select.fd-select--with-pill .ng-select-container{border-top-right-radius:0;border-bottom-right-radius:0;border-right-width:0}:host ::ng-deep ng-select.fd-select.ng-select-focused:not(.ng-select-opened) .ng-select-container,:host ::ng-deep ng-select.fd-select.ng-select-opened .ng-select-container{border-width:var(--fd-select-interactive-border-width, var(--fd-select-border-width, 1.5px));border-color:var(--fd-select-interactive-border-color, #7FB2FF)}:host ::ng-deep ng-select.fd-select[data-fd-field-state=invalid] .ng-select-container{border-width:var(--fd-select-invalid-border-width, var(--fd-select-border-width, 1.5px));border-color:var(--fd-select-invalid-border-color, #EF4444)}:host ::ng-deep ng-select.fd-select .ng-value-container{align-items:center;min-height:100%;padding-top:var(--fd-select-padding-top, 2px);padding-right:var(--fd-select-padding-right, 12px);padding-bottom:var(--fd-select-padding-bottom, 2px);padding-left:var(--fd-select-padding-left, 12px);gap:4px}:host ::ng-deep ng-select.fd-select .ng-placeholder,:host ::ng-deep ng-select.fd-select .ng-value-label,:host ::ng-deep ng-select.fd-select .ng-input>input{font-family:inherit;color:var(--fd-select-text-color, #1C2431);font-size:var(--fd-select-font-size, 14px);font-weight:var(--fd-select-font-weight, 400);line-height:var(--fd-select-line-height, 20px)}:host ::ng-deep ng-select.fd-select .ng-placeholder{color:#1c243166}:host ::ng-deep ng-select.fd-select .ng-select-container.ng-has-value .ng-placeholder{display:none}:host ::ng-deep ng-select.fd-select .ng-arrow-wrapper{padding-right:var(--fd-select-arrow-padding-right, 12px)}:host ::ng-deep ng-select.fd-select.fd-select--with-pill .ng-arrow-wrapper,:host ::ng-deep ng-select.fd-select.fd-select--with-pill .ng-clear-wrapper{display:none}:host ::ng-deep ng-select.fd-select .ng-arrow{border-color:var(--fd-select-icon-color, rgba(28, 36, 49, .6)) transparent transparent}:host ::ng-deep ng-select.fd-select .ng-clear-wrapper{color:var(--fd-select-icon-color, rgba(28, 36, 49, .6))}:host ::ng-deep .ng-dropdown-panel{border:1px solid #E6EAF0;border-radius:8px;background:#fff;box-shadow:0 10px 30px #0000001f}:host ::ng-deep .ng-dropdown-panel .ng-option{padding:10px 14px;font-size:14px;line-height:20px;background:#fff;color:#1c2431}:host ::ng-deep .ng-dropdown-panel .ng-option.ng-option-marked{background:#7fb2ff14;color:#1c2431}:host ::ng-deep .ng-dropdown-panel .ng-option.ng-option-selected{background:#7fb2ff24;color:#1c2431}.fd-select-pill{display:inline-flex;align-items:center;gap:8px;height:var(--fd-select-height, 100%);min-height:var(--fd-select-min-height, 30px);padding:0 12px;border-style:var(--fd-select-border-style, solid);border-width:var(--fd-select-border-width, 1px);border-color:var(--fd-select-border-color, #3F8CFF);border-left-width:var(--fd-select-border-left-width, 1px);border-left-style:var(--fd-select-border-left-style, solid);border-left-color:var(--fd-select-border-left-color, var(--fd-select-border-color, #3F8CFF));border-top-right-radius:var(--fd-select-border-top-right-radius, var(--fd-select-border-radius, 4px));border-bottom-right-radius:var(--fd-select-border-bottom-right-radius, var(--fd-select-border-radius, 4px));border-top-left-radius:0;border-bottom-left-radius:0;background:var(--fd-select-background-color, #FFFFFF);color:var(--fd-select-text-color, #1C2431);font-size:var(--fd-select-font-size, 14px);font-weight:var(--fd-select-font-weight, 400);line-height:var(--fd-select-line-height, 20px);box-shadow:var(--fd-select-box-shadow, none);white-space:nowrap;cursor:pointer}.fd-select-pill:disabled{cursor:default;opacity:.7}.fd-select-pill__arrow{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid var(--fd-select-icon-color, rgba(28, 36, 49, .6))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: NgSelectComponent, selector: "ng-select", inputs: ["bindLabel", "bindValue", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "appearance", "dropdownPosition", "appendTo", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "isOpen", "items", "compareWith", "clearSearchOnAdd", "deselectOnClick", "keyDownFn"], outputs: ["blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"] }] });
|
|
31221
33456
|
}
|
|
31222
33457
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SelectWidgetComponent, decorators: [{
|
|
31223
33458
|
type: Component,
|
|
@@ -31297,7 +33532,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
31297
33532
|
<p [id]="helpTextId" [class]="fieldHelpClass" data-fd="field-help">{{ config.helpText }}</p>
|
|
31298
33533
|
}
|
|
31299
33534
|
</div>
|
|
31300
|
-
`, styles: [":host ::ng-deep ng-select.fd-select{display:block;min-height:0;color:var(--fd-select-text-color, #1C2431)}.fd-select-composite{display:flex;width:100%;min-width:0}:host ::ng-deep ng-select.fd-select .ng-select-container{height:var(--fd-select-height, 100%);min-height:var(--fd-select-min-height,
|
|
33535
|
+
`, styles: [":host ::ng-deep ng-select.fd-select{display:block;min-height:0;color:var(--fd-select-text-color, #1C2431)}.fd-select-composite{display:flex;width:100%;min-width:0}:host ::ng-deep ng-select.fd-select .ng-select-container{height:var(--fd-select-height, 100%);min-height:var(--fd-select-min-height, 30px);border-style:var(--fd-select-border-style, solid);border-width:var(--fd-select-border-width, 1.5px);border-color:var(--fd-select-border-color, #3F8CFF);border-top-style:var(--fd-select-border-top-style, var(--fd-select-border-style, solid));border-right-style:var(--fd-select-border-right-style, var(--fd-select-border-style, solid));border-bottom-style:var(--fd-select-border-bottom-style, var(--fd-select-border-style, solid));border-left-style:var(--fd-select-border-left-style, var(--fd-select-border-style, solid));border-top-width:var(--fd-select-border-top-width, var(--fd-select-border-width, 1.5px));border-right-width:var(--fd-select-border-right-width, var(--fd-select-border-width, 1.5px));border-bottom-width:var(--fd-select-border-bottom-width, var(--fd-select-border-width, 1.5px));border-left-width:var(--fd-select-border-left-width, var(--fd-select-border-width, 1.5px));border-top-color:var(--fd-select-border-top-color, var(--fd-select-border-color, #3F8CFF));border-right-color:var(--fd-select-border-right-color, var(--fd-select-border-color, #3F8CFF));border-bottom-color:var(--fd-select-border-bottom-color, var(--fd-select-border-color, #3F8CFF));border-left-color:var(--fd-select-border-left-color, var(--fd-select-border-color, #3F8CFF));border-radius:var(--fd-select-border-radius, 4px);border-top-left-radius:var(--fd-select-border-top-left-radius, var(--fd-select-border-radius, 4px));border-top-right-radius:var(--fd-select-border-top-right-radius, var(--fd-select-border-radius, 4px));border-bottom-right-radius:var(--fd-select-border-bottom-right-radius, var(--fd-select-border-radius, 4px));border-bottom-left-radius:var(--fd-select-border-bottom-left-radius, var(--fd-select-border-radius, 4px));background:var(--fd-select-background-color, #FFFFFF);box-shadow:var(--fd-select-box-shadow, none);transition:border-color .2s ease,box-shadow .2s ease}:host ::ng-deep ng-select.fd-select:hover .ng-select-container{border-color:var(--fd-select-hover-border-color, var(--fd-select-border-color, #3F8CFF))}:host ::ng-deep ng-select.fd-select.fd-select--with-pill .ng-select-container{border-top-right-radius:0;border-bottom-right-radius:0;border-right-width:0}:host ::ng-deep ng-select.fd-select.ng-select-focused:not(.ng-select-opened) .ng-select-container,:host ::ng-deep ng-select.fd-select.ng-select-opened .ng-select-container{border-width:var(--fd-select-interactive-border-width, var(--fd-select-border-width, 1.5px));border-color:var(--fd-select-interactive-border-color, #7FB2FF)}:host ::ng-deep ng-select.fd-select[data-fd-field-state=invalid] .ng-select-container{border-width:var(--fd-select-invalid-border-width, var(--fd-select-border-width, 1.5px));border-color:var(--fd-select-invalid-border-color, #EF4444)}:host ::ng-deep ng-select.fd-select .ng-value-container{align-items:center;min-height:100%;padding-top:var(--fd-select-padding-top, 2px);padding-right:var(--fd-select-padding-right, 12px);padding-bottom:var(--fd-select-padding-bottom, 2px);padding-left:var(--fd-select-padding-left, 12px);gap:4px}:host ::ng-deep ng-select.fd-select .ng-placeholder,:host ::ng-deep ng-select.fd-select .ng-value-label,:host ::ng-deep ng-select.fd-select .ng-input>input{font-family:inherit;color:var(--fd-select-text-color, #1C2431);font-size:var(--fd-select-font-size, 14px);font-weight:var(--fd-select-font-weight, 400);line-height:var(--fd-select-line-height, 20px)}:host ::ng-deep ng-select.fd-select .ng-placeholder{color:#1c243166}:host ::ng-deep ng-select.fd-select .ng-select-container.ng-has-value .ng-placeholder{display:none}:host ::ng-deep ng-select.fd-select .ng-arrow-wrapper{padding-right:var(--fd-select-arrow-padding-right, 12px)}:host ::ng-deep ng-select.fd-select.fd-select--with-pill .ng-arrow-wrapper,:host ::ng-deep ng-select.fd-select.fd-select--with-pill .ng-clear-wrapper{display:none}:host ::ng-deep ng-select.fd-select .ng-arrow{border-color:var(--fd-select-icon-color, rgba(28, 36, 49, .6)) transparent transparent}:host ::ng-deep ng-select.fd-select .ng-clear-wrapper{color:var(--fd-select-icon-color, rgba(28, 36, 49, .6))}:host ::ng-deep .ng-dropdown-panel{border:1px solid #E6EAF0;border-radius:8px;background:#fff;box-shadow:0 10px 30px #0000001f}:host ::ng-deep .ng-dropdown-panel .ng-option{padding:10px 14px;font-size:14px;line-height:20px;background:#fff;color:#1c2431}:host ::ng-deep .ng-dropdown-panel .ng-option.ng-option-marked{background:#7fb2ff14;color:#1c2431}:host ::ng-deep .ng-dropdown-panel .ng-option.ng-option-selected{background:#7fb2ff24;color:#1c2431}.fd-select-pill{display:inline-flex;align-items:center;gap:8px;height:var(--fd-select-height, 100%);min-height:var(--fd-select-min-height, 30px);padding:0 12px;border-style:var(--fd-select-border-style, solid);border-width:var(--fd-select-border-width, 1px);border-color:var(--fd-select-border-color, #3F8CFF);border-left-width:var(--fd-select-border-left-width, 1px);border-left-style:var(--fd-select-border-left-style, solid);border-left-color:var(--fd-select-border-left-color, var(--fd-select-border-color, #3F8CFF));border-top-right-radius:var(--fd-select-border-top-right-radius, var(--fd-select-border-radius, 4px));border-bottom-right-radius:var(--fd-select-border-bottom-right-radius, var(--fd-select-border-radius, 4px));border-top-left-radius:0;border-bottom-left-radius:0;background:var(--fd-select-background-color, #FFFFFF);color:var(--fd-select-text-color, #1C2431);font-size:var(--fd-select-font-size, 14px);font-weight:var(--fd-select-font-weight, 400);line-height:var(--fd-select-line-height, 20px);box-shadow:var(--fd-select-box-shadow, none);white-space:nowrap;cursor:pointer}.fd-select-pill:disabled{cursor:default;opacity:.7}.fd-select-pill__arrow{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid var(--fd-select-icon-color, rgba(28, 36, 49, .6))}\n"] }]
|
|
31301
33536
|
}], propDecorators: { ngSelectComponent: [{
|
|
31302
33537
|
type: ViewChild,
|
|
31303
33538
|
args: [NgSelectComponent]
|
|
@@ -31332,6 +33567,7 @@ class SearchWidgetComponent {
|
|
|
31332
33567
|
requestId = 0;
|
|
31333
33568
|
syncingFromQuery = false;
|
|
31334
33569
|
selectingOption = false;
|
|
33570
|
+
pendingSelectedLabel;
|
|
31335
33571
|
focused = false;
|
|
31336
33572
|
hovered = false;
|
|
31337
33573
|
blurCloseTimeout = null;
|
|
@@ -31388,7 +33624,7 @@ class SearchWidgetComponent {
|
|
|
31388
33624
|
}
|
|
31389
33625
|
ngOnInit() {
|
|
31390
33626
|
this.syncEnabledState();
|
|
31391
|
-
this.queryControl.setValue(this.
|
|
33627
|
+
this.queryControl.setValue(this.getDisplayValue(this.control.value), { emitEvent: false });
|
|
31392
33628
|
this.queryControl.valueChanges
|
|
31393
33629
|
.pipe(debounceTime(this.getDebounceMs()), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
|
|
31394
33630
|
.subscribe(query => {
|
|
@@ -31398,6 +33634,16 @@ class SearchWidgetComponent {
|
|
|
31398
33634
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
31399
33635
|
.subscribe(value => {
|
|
31400
33636
|
if (this.engine) {
|
|
33637
|
+
if (this.pendingSelectedLabel !== undefined) {
|
|
33638
|
+
this.setStoredFieldLabel(this.pendingSelectedLabel);
|
|
33639
|
+
this.pendingSelectedLabel = undefined;
|
|
33640
|
+
}
|
|
33641
|
+
else if (this.syncingFromQuery) {
|
|
33642
|
+
this.setStoredFieldLabel(undefined);
|
|
33643
|
+
}
|
|
33644
|
+
else {
|
|
33645
|
+
this.setStoredFieldLabel(resolveOptionFieldLabel(value, this.options, this.getStoredFieldLabel()));
|
|
33646
|
+
}
|
|
31401
33647
|
this.engine.setValue(this.config.name, value);
|
|
31402
33648
|
this.runtimeFieldDataAccessRegistry.invalidateFieldAndDescendants(this.engine, this.config.id);
|
|
31403
33649
|
this.engine.emitUiEvent({
|
|
@@ -31413,7 +33659,7 @@ class SearchWidgetComponent {
|
|
|
31413
33659
|
if (this.syncingFromQuery || this.selectingOption) {
|
|
31414
33660
|
return;
|
|
31415
33661
|
}
|
|
31416
|
-
this.queryControl.setValue(this.
|
|
33662
|
+
this.queryControl.setValue(this.getDisplayValue(value), { emitEvent: false });
|
|
31417
33663
|
});
|
|
31418
33664
|
if (this.engine) {
|
|
31419
33665
|
const dataSourceUpdates$ = this.engine.dataSourceUpdates$;
|
|
@@ -31529,6 +33775,7 @@ class SearchWidgetComponent {
|
|
|
31529
33775
|
}
|
|
31530
33776
|
selectOption(option) {
|
|
31531
33777
|
this.selectingOption = true;
|
|
33778
|
+
this.pendingSelectedLabel = String(option.label ?? '');
|
|
31532
33779
|
this.queryControl.setValue(String(option.label ?? ''), { emitEvent: false });
|
|
31533
33780
|
this.options = [];
|
|
31534
33781
|
this.activeOptionIndex = -1;
|
|
@@ -31666,6 +33913,25 @@ class SearchWidgetComponent {
|
|
|
31666
33913
|
return '';
|
|
31667
33914
|
return String(value);
|
|
31668
33915
|
}
|
|
33916
|
+
getDisplayValue(value) {
|
|
33917
|
+
const fieldLabel = this.getStoredFieldLabel();
|
|
33918
|
+
if (typeof fieldLabel === 'string' && fieldLabel.length > 0) {
|
|
33919
|
+
return fieldLabel;
|
|
33920
|
+
}
|
|
33921
|
+
return this.asQueryString(value);
|
|
33922
|
+
}
|
|
33923
|
+
getStoredFieldLabel() {
|
|
33924
|
+
if (!this.engine || typeof this.engine.getFieldLabel !== 'function') {
|
|
33925
|
+
return undefined;
|
|
33926
|
+
}
|
|
33927
|
+
return this.engine.getFieldLabel(this.config.name);
|
|
33928
|
+
}
|
|
33929
|
+
setStoredFieldLabel(label) {
|
|
33930
|
+
if (!this.engine || typeof this.engine.setFieldLabel !== 'function') {
|
|
33931
|
+
return;
|
|
33932
|
+
}
|
|
33933
|
+
this.engine.setFieldLabel(this.config.name, label);
|
|
33934
|
+
}
|
|
31669
33935
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SearchWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
31670
33936
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SearchWidgetComponent, isStandalone: true, selector: "app-search-widget", inputs: { config: "config", engine: "engine", control: "control" }, ngImport: i0, template: `
|
|
31671
33937
|
<div [class]="fieldContainerClass"
|
|
@@ -32428,6 +34694,7 @@ class RadioWidgetComponent {
|
|
|
32428
34694
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
32429
34695
|
.subscribe(val => {
|
|
32430
34696
|
if (this.engine) {
|
|
34697
|
+
this.setStoredFieldLabel(resolveOptionFieldLabel(val, this.options, this.getStoredFieldLabel()));
|
|
32431
34698
|
this.engine.setValue(this.config.name, val);
|
|
32432
34699
|
this.engine.emitUiEvent({ fieldId: this.config.id, fieldName: this.config.name, type: 'change', value: val });
|
|
32433
34700
|
if (this.control.dirty) {
|
|
@@ -32436,7 +34703,12 @@ class RadioWidgetComponent {
|
|
|
32436
34703
|
}
|
|
32437
34704
|
});
|
|
32438
34705
|
this.syncEnabledState();
|
|
32439
|
-
|
|
34706
|
+
if (this.areApiCallsSuppressed() && this.hasSelectedValue()) {
|
|
34707
|
+
this.options = this.withSelectedValueFallbackOptions([]);
|
|
34708
|
+
}
|
|
34709
|
+
else {
|
|
34710
|
+
await this.loadOptions();
|
|
34711
|
+
}
|
|
32440
34712
|
// Dependencies
|
|
32441
34713
|
const dependencyIds = this.getDependencyFieldIds();
|
|
32442
34714
|
if (this.engine) {
|
|
@@ -32492,7 +34764,10 @@ class RadioWidgetComponent {
|
|
|
32492
34764
|
// Radio doesn't typically support search, so just get options
|
|
32493
34765
|
opts = await this.dataProvider.getOptions(this.config, this.engine);
|
|
32494
34766
|
if (this.requestId === reqId) {
|
|
32495
|
-
this.options = opts;
|
|
34767
|
+
this.options = this.withSelectedValueFallbackOptions(opts);
|
|
34768
|
+
if (this.engine) {
|
|
34769
|
+
this.setStoredFieldLabel(resolveOptionFieldLabel(this.control.value, this.options, this.getStoredFieldLabel()));
|
|
34770
|
+
}
|
|
32496
34771
|
this.loading = false;
|
|
32497
34772
|
this.loadError = null;
|
|
32498
34773
|
this.cdr.markForCheck();
|
|
@@ -32502,7 +34777,7 @@ class RadioWidgetComponent {
|
|
|
32502
34777
|
if (this.requestId === reqId) {
|
|
32503
34778
|
this.loading = false;
|
|
32504
34779
|
this.loadError = 'Failed to load options.';
|
|
32505
|
-
this.options = this.config.staticOptions || [];
|
|
34780
|
+
this.options = this.withSelectedValueFallbackOptions(this.config.staticOptions || []);
|
|
32506
34781
|
this.cdr.markForCheck();
|
|
32507
34782
|
}
|
|
32508
34783
|
}
|
|
@@ -32551,6 +34826,38 @@ class RadioWidgetComponent {
|
|
|
32551
34826
|
this.control.disable({ emitEvent: false });
|
|
32552
34827
|
}
|
|
32553
34828
|
}
|
|
34829
|
+
areApiCallsSuppressed() {
|
|
34830
|
+
return areEngineApiCallsSuppressed(this.engine);
|
|
34831
|
+
}
|
|
34832
|
+
hasSelectedValue() {
|
|
34833
|
+
return this.control.value !== undefined && this.control.value !== null && this.control.value !== '';
|
|
34834
|
+
}
|
|
34835
|
+
withSelectedValueFallbackOptions(options) {
|
|
34836
|
+
const fallback = buildFallbackOptions(this.control.value, this.getStoredFieldLabel());
|
|
34837
|
+
if (fallback.length === 0) {
|
|
34838
|
+
return options;
|
|
34839
|
+
}
|
|
34840
|
+
const merged = [...options];
|
|
34841
|
+
for (const option of fallback) {
|
|
34842
|
+
if (merged.some(existing => Object.is(existing.value, option.value) || String(existing.value) === String(option.value))) {
|
|
34843
|
+
continue;
|
|
34844
|
+
}
|
|
34845
|
+
merged.unshift(option);
|
|
34846
|
+
}
|
|
34847
|
+
return merged;
|
|
34848
|
+
}
|
|
34849
|
+
getStoredFieldLabel() {
|
|
34850
|
+
if (!this.engine || typeof this.engine.getFieldLabel !== 'function') {
|
|
34851
|
+
return undefined;
|
|
34852
|
+
}
|
|
34853
|
+
return this.engine.getFieldLabel(this.config.name);
|
|
34854
|
+
}
|
|
34855
|
+
setStoredFieldLabel(label) {
|
|
34856
|
+
if (!this.engine || typeof this.engine.setFieldLabel !== 'function') {
|
|
34857
|
+
return;
|
|
34858
|
+
}
|
|
34859
|
+
this.engine.setFieldLabel(this.config.name, label);
|
|
34860
|
+
}
|
|
32554
34861
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RadioWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
32555
34862
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: RadioWidgetComponent, isStandalone: true, selector: "app-radio-widget", inputs: { config: "config", engine: "engine", control: "control" }, usesOnChanges: true, ngImport: i0, template: `
|
|
32556
34863
|
<div [class]="fieldContainerClass"
|
|
@@ -32679,6 +34986,7 @@ class CheckboxGroupWidgetComponent {
|
|
|
32679
34986
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
32680
34987
|
.subscribe(val => {
|
|
32681
34988
|
if (this.engine) {
|
|
34989
|
+
this.setStoredFieldLabel(resolveOptionFieldLabel(val, this.options, this.getStoredFieldLabel()));
|
|
32682
34990
|
this.engine.setValue(this.config.name, val);
|
|
32683
34991
|
this.engine.emitUiEvent({ fieldId: this.config.id, fieldName: this.config.name, type: 'change', value: val });
|
|
32684
34992
|
if (this.control.dirty) {
|
|
@@ -32687,7 +34995,12 @@ class CheckboxGroupWidgetComponent {
|
|
|
32687
34995
|
}
|
|
32688
34996
|
});
|
|
32689
34997
|
// this.syncEnabledState(); // Checkboxes individually disabled via [disabled] binding
|
|
32690
|
-
|
|
34998
|
+
if (this.areApiCallsSuppressed() && this.hasSelectedValue()) {
|
|
34999
|
+
this.options = this.withSelectedValueFallbackOptions([]);
|
|
35000
|
+
}
|
|
35001
|
+
else {
|
|
35002
|
+
await this.loadOptions();
|
|
35003
|
+
}
|
|
32691
35004
|
// Dependencies
|
|
32692
35005
|
const dependencyIds = this.getDependencyFieldIds();
|
|
32693
35006
|
if (this.engine) {
|
|
@@ -32742,7 +35055,10 @@ class CheckboxGroupWidgetComponent {
|
|
|
32742
35055
|
let opts = [];
|
|
32743
35056
|
opts = await this.dataProvider.getOptions(this.config, this.engine);
|
|
32744
35057
|
if (this.requestId === reqId) {
|
|
32745
|
-
this.options = opts;
|
|
35058
|
+
this.options = this.withSelectedValueFallbackOptions(opts);
|
|
35059
|
+
if (this.engine) {
|
|
35060
|
+
this.setStoredFieldLabel(resolveOptionFieldLabel(this.control.value, this.options, this.getStoredFieldLabel()));
|
|
35061
|
+
}
|
|
32746
35062
|
this.loading = false;
|
|
32747
35063
|
this.loadError = null;
|
|
32748
35064
|
this.cdr.markForCheck();
|
|
@@ -32752,7 +35068,7 @@ class CheckboxGroupWidgetComponent {
|
|
|
32752
35068
|
if (this.requestId === reqId) {
|
|
32753
35069
|
this.loading = false;
|
|
32754
35070
|
this.loadError = 'Failed to load options.';
|
|
32755
|
-
this.options = this.config.staticOptions || [];
|
|
35071
|
+
this.options = this.withSelectedValueFallbackOptions(this.config.staticOptions || []);
|
|
32756
35072
|
this.cdr.markForCheck();
|
|
32757
35073
|
}
|
|
32758
35074
|
}
|
|
@@ -32820,6 +35136,38 @@ class CheckboxGroupWidgetComponent {
|
|
|
32820
35136
|
}
|
|
32821
35137
|
}
|
|
32822
35138
|
}
|
|
35139
|
+
areApiCallsSuppressed() {
|
|
35140
|
+
return areEngineApiCallsSuppressed(this.engine);
|
|
35141
|
+
}
|
|
35142
|
+
hasSelectedValue() {
|
|
35143
|
+
return Array.isArray(this.control.value) && this.control.value.length > 0;
|
|
35144
|
+
}
|
|
35145
|
+
withSelectedValueFallbackOptions(options) {
|
|
35146
|
+
const fallback = buildFallbackOptions(this.control.value, this.getStoredFieldLabel());
|
|
35147
|
+
if (fallback.length === 0) {
|
|
35148
|
+
return options;
|
|
35149
|
+
}
|
|
35150
|
+
const merged = [...options];
|
|
35151
|
+
for (const option of fallback) {
|
|
35152
|
+
if (merged.some(existing => Object.is(existing.value, option.value) || String(existing.value) === String(option.value))) {
|
|
35153
|
+
continue;
|
|
35154
|
+
}
|
|
35155
|
+
merged.unshift(option);
|
|
35156
|
+
}
|
|
35157
|
+
return merged;
|
|
35158
|
+
}
|
|
35159
|
+
getStoredFieldLabel() {
|
|
35160
|
+
if (!this.engine || typeof this.engine.getFieldLabel !== 'function') {
|
|
35161
|
+
return undefined;
|
|
35162
|
+
}
|
|
35163
|
+
return this.engine.getFieldLabel(this.config.name);
|
|
35164
|
+
}
|
|
35165
|
+
setStoredFieldLabel(label) {
|
|
35166
|
+
if (!this.engine || typeof this.engine.setFieldLabel !== 'function') {
|
|
35167
|
+
return;
|
|
35168
|
+
}
|
|
35169
|
+
this.engine.setFieldLabel(this.config.name, label);
|
|
35170
|
+
}
|
|
32823
35171
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CheckboxGroupWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
32824
35172
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: CheckboxGroupWidgetComponent, isStandalone: true, selector: "app-checkbox-group-widget", inputs: { config: "config", engine: "engine", control: "control" }, usesOnChanges: true, ngImport: i0, template: `
|
|
32825
35173
|
<div [class]="fieldContainerClass"
|
|
@@ -33485,7 +35833,7 @@ class RepeatableGroupWidgetComponent {
|
|
|
33485
35833
|
</div>
|
|
33486
35834
|
</ng-template>
|
|
33487
35835
|
</div>
|
|
33488
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: LayoutNodeComponent, selector: "app-layout-node", inputs: ["node", "engine", "fields", "designMode", "readOnlyMode", "scopePath", "device", "breakpoint", "connectedDropLists"], outputs: ["nodeDrop", "nodeSelect"] }] });
|
|
35836
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: LayoutNodeComponent, selector: "app-layout-node", inputs: ["node", "engine", "fields", "designMode", "showLayoutGuides", "readOnlyMode", "scopePath", "device", "breakpoint", "connectedDropLists"], outputs: ["nodeDrop", "nodeSelect"] }] });
|
|
33489
35837
|
}
|
|
33490
35838
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RepeatableGroupWidgetComponent, decorators: [{
|
|
33491
35839
|
type: Component,
|
|
@@ -37799,6 +40147,116 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
37799
40147
|
args: [DOCUMENT]
|
|
37800
40148
|
}] }] });
|
|
37801
40149
|
|
|
40150
|
+
class AiToolRegistryService {
|
|
40151
|
+
state;
|
|
40152
|
+
widgetDefs;
|
|
40153
|
+
eventApis;
|
|
40154
|
+
plugins;
|
|
40155
|
+
toolByName;
|
|
40156
|
+
constructor() {
|
|
40157
|
+
this.state = inject(DesignerStateService);
|
|
40158
|
+
const injectedWidgetDefs = inject(WIDGET_DEFINITIONS, { optional: true }) ?? [];
|
|
40159
|
+
this.widgetDefs = injectedWidgetDefs.flat();
|
|
40160
|
+
this.eventApis = [];
|
|
40161
|
+
this.plugins = [FORM_DESIGNER_AI_TOOL_PLUGIN];
|
|
40162
|
+
this.toolByName = this.buildToolIndex(this.plugins);
|
|
40163
|
+
}
|
|
40164
|
+
/**
|
|
40165
|
+
* Create an instance directly for testing without Angular DI.
|
|
40166
|
+
*/
|
|
40167
|
+
static forTest(state, eventApis, plugins, widgetDefs) {
|
|
40168
|
+
const instance = Object.create(AiToolRegistryService.prototype);
|
|
40169
|
+
instance.state = state;
|
|
40170
|
+
instance.eventApis = eventApis ? [...eventApis] : [];
|
|
40171
|
+
instance.widgetDefs = widgetDefs ? [...widgetDefs] : [];
|
|
40172
|
+
instance.plugins = plugins?.length ? [...plugins] : [FORM_DESIGNER_AI_TOOL_PLUGIN];
|
|
40173
|
+
instance.toolByName = instance.buildToolIndex(instance.plugins);
|
|
40174
|
+
return instance;
|
|
40175
|
+
}
|
|
40176
|
+
describeTools() {
|
|
40177
|
+
return this.plugins.flatMap((plugin) => plugin.tools.map((tool) => ({
|
|
40178
|
+
name: tool.name,
|
|
40179
|
+
description: tool.summary,
|
|
40180
|
+
summary: tool.summary,
|
|
40181
|
+
domain: tool.domain,
|
|
40182
|
+
readOnly: tool.readOnly,
|
|
40183
|
+
tags: tool.tags,
|
|
40184
|
+
whenToUse: tool.whenToUse,
|
|
40185
|
+
whenNotToUse: tool.whenNotToUse,
|
|
40186
|
+
exampleIntents: tool.exampleIntents,
|
|
40187
|
+
requiresSelection: tool.requiresSelection,
|
|
40188
|
+
requiresCapabilities: tool.requiresCapabilities,
|
|
40189
|
+
requiredAuthScopes: tool.requiredAuthScopes,
|
|
40190
|
+
parametersSchema: tool.parametersSchema,
|
|
40191
|
+
})));
|
|
40192
|
+
}
|
|
40193
|
+
async execute(name, args) {
|
|
40194
|
+
const tool = this.toolByName.get(name);
|
|
40195
|
+
if (!tool) {
|
|
40196
|
+
return {
|
|
40197
|
+
ok: false,
|
|
40198
|
+
result: null,
|
|
40199
|
+
error: `Unknown tool: "${name}"`,
|
|
40200
|
+
};
|
|
40201
|
+
}
|
|
40202
|
+
const context = this.createContext();
|
|
40203
|
+
if (tool.isApplicable && !tool.isApplicable(context)) {
|
|
40204
|
+
return {
|
|
40205
|
+
ok: false,
|
|
40206
|
+
result: null,
|
|
40207
|
+
error: `Tool "${name}" is not applicable in current context.`,
|
|
40208
|
+
};
|
|
40209
|
+
}
|
|
40210
|
+
const result = await tool.execute(context, args);
|
|
40211
|
+
return result;
|
|
40212
|
+
}
|
|
40213
|
+
getDiscoveryContext() {
|
|
40214
|
+
return {
|
|
40215
|
+
workspace: 'designer',
|
|
40216
|
+
readOnly: this.state.isReadOnly(),
|
|
40217
|
+
hasSelection: !!this.state.selectedNodeId(),
|
|
40218
|
+
capabilities: {
|
|
40219
|
+
eventApis: this.eventApis.length > 0,
|
|
40220
|
+
widgetCatalog: this.widgetDefs.length > 0,
|
|
40221
|
+
},
|
|
40222
|
+
};
|
|
40223
|
+
}
|
|
40224
|
+
/** Allow host/shell to update available event APIs at runtime. */
|
|
40225
|
+
setEventApis(apis) {
|
|
40226
|
+
this.eventApis = [...apis];
|
|
40227
|
+
}
|
|
40228
|
+
/** Allow host/shell to update widget catalog at runtime. */
|
|
40229
|
+
setWidgetDefinitions(widgetDefs) {
|
|
40230
|
+
this.widgetDefs = [...widgetDefs];
|
|
40231
|
+
}
|
|
40232
|
+
/** Register additional plain TS plugins without requiring Angular DI contracts. */
|
|
40233
|
+
registerPlugin(plugin) {
|
|
40234
|
+
this.plugins = [...this.plugins, plugin];
|
|
40235
|
+
this.toolByName = this.buildToolIndex(this.plugins);
|
|
40236
|
+
}
|
|
40237
|
+
createContext() {
|
|
40238
|
+
return {
|
|
40239
|
+
state: this.state,
|
|
40240
|
+
eventApis: this.eventApis,
|
|
40241
|
+
widgetDefs: this.widgetDefs,
|
|
40242
|
+
};
|
|
40243
|
+
}
|
|
40244
|
+
buildToolIndex(plugins) {
|
|
40245
|
+
const index = new Map();
|
|
40246
|
+
for (const plugin of plugins) {
|
|
40247
|
+
for (const tool of plugin.tools) {
|
|
40248
|
+
index.set(tool.name, tool);
|
|
40249
|
+
}
|
|
40250
|
+
}
|
|
40251
|
+
return index;
|
|
40252
|
+
}
|
|
40253
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AiToolRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
40254
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AiToolRegistryService });
|
|
40255
|
+
}
|
|
40256
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AiToolRegistryService, decorators: [{
|
|
40257
|
+
type: Injectable
|
|
40258
|
+
}], ctorParameters: () => [] });
|
|
40259
|
+
|
|
37802
40260
|
class InMemoryDataCatalogService extends DataCatalog {
|
|
37803
40261
|
sources = [];
|
|
37804
40262
|
listSources() {
|
|
@@ -37971,5 +40429,5 @@ function provideHttpDataSourceClient(config) {
|
|
|
37971
40429
|
* Generated bundle index. Do not edit.
|
|
37972
40430
|
*/
|
|
37973
40431
|
|
|
37974
|
-
export { APPEARANCE_FIELDS, AiToolRegistryService, CONTENT_TEXT_CLASS, CONTENT_TEXT_MUTED_CLASS, CORE_DESIGNER_PLUGINS, CURRENT_SCHEMA_VERSION, DATA_PROVIDER, DATA_SOURCE_CLIENT, DEFAULT_TEMPLATE_LIBRARY, DEFAULT_WEBSITE_SECTIONS, DEFAULT_WIDGET_PACKS, DESIGNER_PLUGINS, DESIGNER_SECTIONS, DataCatalog, DataPanelComponent, DataProvider, DefaultDataProvider, DefaultDataSourceClient, DefaultFileUploadClient, DesignerContext, DesignerStateService, DynamicPropertiesComponent, EFFECTS_FIELDS, EMAIL_SAFE_STYLE_SECTIONS, EMAIL_WIDGETS, EmailRendererComponent, EventsPanelComponent, EventsWorkspaceComponent, FIELD_CHOICE_LABEL_CLASS, FIELD_CHOICE_SURFACE_CLASS, FIELD_CONTAINER_CLASS, FIELD_ERROR_CLASS, FIELD_HELP_CLASS, FIELD_LABEL_CLASS, FIELD_OPTION_CLASS, FIELD_REQUIRED_CLASS, FIELD_RESULTS_PANEL_CLASS, FIELD_WIDGETS, FILE_UPLOAD_CARD_CLASS, FILE_UPLOAD_CLIENT, FORM_DESIGNER_AI_TOOL_PLUGIN, FULL_WEB_STYLE_SECTIONS, FieldPaletteComponent, FormDesignerShellComponent, FormEngine, FormViewerComponent, GlobalDataManagerComponent, HTTP_DATA_SOURCE_CLIENT_CONFIG, HttpDataSourceClient, InMemoryDataCatalogService, InspectorAdvancedSectionComponent, InspectorBackgroundsSectionComponent, InspectorBordersSectionComponent, InspectorEffectsSectionComponent, InspectorLayoutSectionComponent, InspectorPositionSectionComponent, InspectorSizeSectionComponent, InspectorSpacingSectionComponent, InspectorSpinInputComponent, InspectorTypographySectionComponent, JsonFormDesignerComponent, JsonFormRendererComponent, LAYOUT_FIELDS, LayoutCanvasComponent, LayoutNodeComponent, OUTLINED_FIELD_BORDER_WIDTH, OUTLINED_FIELD_IDLE_BORDER_COLOR, OUTLINED_FIELD_INTERACTIVE_BORDER_COLOR, OUTLINED_FIELD_INVALID_BORDER_COLOR, PAGE_WIDGETS, PropertiesPanelComponent, RulesPanelComponent, RuntimeFieldDataAccessRegistryService, SELECT_THEME_HOOKS, SELECT_THEME_TOKENS, SPACING_BOX_MODEL_FIELD, SPACING_MARGIN_FIELDS, SPACING_PADDING_FIELDS, STANDARD_FORM_STYLE_SECTIONS, STYLE_APPEARANCE_SECTION, STYLE_EFFECTS_SECTION, STYLE_LAYOUT_SECTION, STYLE_SECTIONS, STYLE_SPACING_SECTION, STYLE_TRANSFORM_SECTION, STYLE_TYPOGRAPHY_SECTION, TABLE_CELL_CLASS, TABLE_EMPTY_CLASS, TABLE_GRID_CLASS, TABLE_HEAD_CELL_CLASS, TABLE_HEAD_CLASS, TABLE_ICON_BUTTON_CLASS, TABLE_ROOT_CLASS, TABLE_ROW_CLASS, TABLE_TOOLBAR_CLASS, TRANSFORM_FIELDS, TYPOGRAPHY_FIELDS, ThemeService, UiAccordionComponent, UiBoxModelComponent, UiColorSwatchComponent, UiDimensionComponent, UiEdgeBoxComponent, UiFieldWrapperComponent, UiInputComponent, UiRangeNumberComponent, UiSelectIconComponent, UiTabComponent, UiTabsComponent, WIDGET_DEFINITIONS, WIDGET_ID_SEPARATOR, WebsiteBrickStudioComponent, WebsiteDesignerShellComponent, WebsitePreviewShellComponent, WebsiteProjectService, WidgetDefinitionResolverService, WidgetInspectorComponent, appendSectionToSchema, buildWidgetId, checkSchemaForApiOnlySources, createDefaultWebsiteBrick, createDefaultWebsiteBricks, createDefaultWebsiteTheme, createEmptySchema, createFormEngine, createPluginContext, createWebsiteBrick, createWebsitePage, createWebsiteProject, defineWidget, flattenPluginWidgets, getButtonClass, getChoiceControlClass, getEffectiveDataConfig, getFileInputClass, getFileUploadShellClass, getHeadingClass, getOutlinedFieldInlineStyle, getTextControlClass, getWidgetsForFlavor, hasWrapperSurfaceStyles, inferSchema, isWidgetVisibleInPalette, mergeAndNormalize, normalizeRuntimeOptions, normalizeStyle$1 as normalizeStyle, parseCsv, parseJsonArray, parseSchema, provideDesignerPlugins, provideHttpDataSourceClient, serializeSchema, slugifyId, splitControlSurfaceStyles, stripEmbeddedSourceData };
|
|
40432
|
+
export { APPEARANCE_FIELDS, AiToolRegistryService, CONTENT_TEXT_CLASS, CONTENT_TEXT_MUTED_CLASS, CORE_DESIGNER_PLUGINS, CURRENT_SCHEMA_VERSION, DATA_PROVIDER, DATA_SOURCE_CLIENT, DEFAULT_TEMPLATE_LIBRARY, DEFAULT_WEBSITE_SECTIONS, DEFAULT_WIDGET_PACKS, DESIGNER_PLUGINS, DESIGNER_SECTIONS, DataCatalog, DataPanelComponent, DataProvider, DefaultDataProvider, DefaultDataSourceClient, DefaultFileUploadClient, DesignerContext, DesignerStateService, DynamicPropertiesComponent, EFFECTS_FIELDS, EMAIL_SAFE_STYLE_SECTIONS, EMAIL_WIDGETS, EmailRendererComponent, EventsPanelComponent, EventsWorkspaceComponent, FIELD_CHOICE_LABEL_CLASS, FIELD_CHOICE_SURFACE_CLASS, FIELD_CONTAINER_CLASS, FIELD_ERROR_CLASS, FIELD_HELP_CLASS, FIELD_LABEL_CLASS, FIELD_OPTION_CLASS, FIELD_REQUIRED_CLASS, FIELD_RESULTS_PANEL_CLASS, FIELD_WIDGETS, FILE_UPLOAD_CARD_CLASS, FILE_UPLOAD_CLIENT, FORM_DESIGNER_AI_TOOL_PLUGIN, FULL_WEB_STYLE_SECTIONS, FieldPaletteComponent, FormDesignerAiFeatureStateService, FormDesignerShellComponent, FormEngine, FormJourneyStateService, FormJourneyViewerComponent, FormViewerComponent, GlobalDataManagerComponent, HTTP_DATA_SOURCE_CLIENT_CONFIG, HttpDataSourceClient, InMemoryDataCatalogService, InspectorAdvancedSectionComponent, InspectorBackgroundsSectionComponent, InspectorBordersSectionComponent, InspectorEffectsSectionComponent, InspectorLayoutSectionComponent, InspectorPositionSectionComponent, InspectorSizeSectionComponent, InspectorSpacingSectionComponent, InspectorSpinInputComponent, InspectorTypographySectionComponent, JsonFormDesignerComponent, JsonFormRendererComponent, LAYOUT_FIELDS, LayoutCanvasComponent, LayoutNodeComponent, OUTLINED_FIELD_BORDER_WIDTH, OUTLINED_FIELD_IDLE_BORDER_COLOR, OUTLINED_FIELD_INTERACTIVE_BORDER_COLOR, OUTLINED_FIELD_INVALID_BORDER_COLOR, PAGE_WIDGETS, PropertiesPanelComponent, RulesPanelComponent, RuntimeFieldDataAccessRegistryService, SELECT_THEME_HOOKS, SELECT_THEME_TOKENS, SPACING_BOX_MODEL_FIELD, SPACING_MARGIN_FIELDS, SPACING_PADDING_FIELDS, STANDARD_FORM_STYLE_SECTIONS, STYLE_APPEARANCE_SECTION, STYLE_EFFECTS_SECTION, STYLE_LAYOUT_SECTION, STYLE_SECTIONS, STYLE_SPACING_SECTION, STYLE_TRANSFORM_SECTION, STYLE_TYPOGRAPHY_SECTION, TABLE_CELL_CLASS, TABLE_EMPTY_CLASS, TABLE_GRID_CLASS, TABLE_HEAD_CELL_CLASS, TABLE_HEAD_CLASS, TABLE_ICON_BUTTON_CLASS, TABLE_ROOT_CLASS, TABLE_ROW_CLASS, TABLE_TOOLBAR_CLASS, TRANSFORM_FIELDS, TYPOGRAPHY_FIELDS, ThemeService, UiAccordionComponent, UiBoxModelComponent, UiColorSwatchComponent, UiDimensionComponent, UiEdgeBoxComponent, UiFieldWrapperComponent, UiInputComponent, UiRangeNumberComponent, UiSelectIconComponent, UiTabComponent, UiTabsComponent, WIDGET_DEFINITIONS, WIDGET_ID_SEPARATOR, WebsiteBrickStudioComponent, WebsiteDesignerShellComponent, WebsitePreviewShellComponent, WebsiteProjectService, WidgetDefinitionResolverService, WidgetInspectorComponent, appendSectionToSchema, buildWidgetId, checkSchemaForApiOnlySources, createDefaultWebsiteBrick, createDefaultWebsiteBricks, createDefaultWebsiteTheme, createEmptySchema, createFormEngine, createFormJourneyPage, createFormJourneyProject, createPluginContext, createWebsiteBrick, createWebsitePage, createWebsiteProject, defineWidget, flattenPluginWidgets, getButtonClass, getChoiceControlClass, getEffectiveDataConfig, getFileInputClass, getFileUploadShellClass, getHeadingClass, getOutlinedFieldInlineStyle, getTextControlClass, getWidgetsForFlavor, hasWrapperSurfaceStyles, inferSchema, isFormJourneyProject, isWidgetVisibleInPalette, mergeAndNormalize, normalizeRuntimeOptions, normalizeStyle$1 as normalizeStyle, normalizeToJourney, parseCsv, parseJsonArray, parseSchema, provideDesignerPlugins, provideFormDesignerAngaiFeature, provideHttpDataSourceClient, serializeSchema, slugifyId, splitControlSurfaceStyles, stripEmbeddedSourceData, unwrapSinglePageJourney };
|
|
37975
40433
|
//# sourceMappingURL=uch-web-ngx-form-designer.mjs.map
|