@yourself.create/ngx-form-designer 0.0.12 → 0.0.13

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.
@@ -329,6 +329,8 @@ class RuleEvaluationService {
329
329
  return value !== null && value !== undefined && value !== '';
330
330
  case 'truthy':
331
331
  return !!value;
332
+ case 'notTruthy':
333
+ return !value;
332
334
  default: return false;
333
335
  }
334
336
  }
@@ -1379,11 +1381,10 @@ class DesignerStateService {
1379
1381
  const originalField = clipboardFields.get(oldRefId);
1380
1382
  if (originalField) {
1381
1383
  const newFieldId = v4();
1382
- const newField = {
1383
- ...originalField,
1384
+ const newField = this.cloneFieldForDuplication(originalField, {
1384
1385
  id: newFieldId,
1385
1386
  name: `${originalField.name}_${Date.now()}_${Math.floor(Math.random() * 1000)}`
1386
- };
1387
+ });
1387
1388
  targetSchema.fields.push(newField);
1388
1389
  newNode.refId = newFieldId;
1389
1390
  }
@@ -2308,12 +2309,11 @@ class DesignerStateService {
2308
2309
  const originalField = scopeFields.find(f => f.id === cloned.refId);
2309
2310
  if (originalField) {
2310
2311
  const newFieldId = v4();
2311
- const newField = {
2312
- ...this.cloneValue(originalField),
2312
+ const newField = this.cloneFieldForDuplication(originalField, {
2313
2313
  id: newFieldId,
2314
2314
  name: `${originalField.name}_copy_${Date.now()}`,
2315
2315
  label: `${originalField.label || 'Field'} (Copy)`
2316
- };
2316
+ });
2317
2317
  scopeFields.push(newField);
2318
2318
  cloned.refId = newFieldId;
2319
2319
  }
@@ -2383,11 +2383,10 @@ class DesignerStateService {
2383
2383
  if (!location)
2384
2384
  return;
2385
2385
  const newFieldId = v4();
2386
- const newField = {
2387
- ...this.cloneValue(location.field),
2386
+ const newField = this.cloneFieldForDuplication(location.field, {
2388
2387
  id: newFieldId,
2389
2388
  name: `${location.field.name}_copy_${Date.now()}`
2390
- };
2389
+ });
2391
2390
  location.schema.fields.push(newField);
2392
2391
  const widgetNode = this.findWidgetByRefId(location.schema.layout, fieldId);
2393
2392
  if (!widgetNode) {
@@ -2914,6 +2913,42 @@ class DesignerStateService {
2914
2913
  cloneValue(value) {
2915
2914
  return structuredClone(value);
2916
2915
  }
2916
+ cloneFieldForDuplication(field, overrides) {
2917
+ const clonedField = this.cloneValue(field);
2918
+ const bindingIdMap = new Map();
2919
+ const events = clonedField.events?.map(binding => {
2920
+ const nextBindingId = v4();
2921
+ bindingIdMap.set(binding.id, nextBindingId);
2922
+ return {
2923
+ ...binding,
2924
+ id: nextBindingId,
2925
+ actions: binding.actions.map(action => {
2926
+ if (action.type !== 'api') {
2927
+ return action;
2928
+ }
2929
+ return {
2930
+ ...action,
2931
+ datasourceId: action.datasourceId ? this.createEventDatasourceId() : action.datasourceId
2932
+ };
2933
+ })
2934
+ };
2935
+ });
2936
+ const dataConfig = clonedField.dataConfig?.eventId && bindingIdMap.has(clonedField.dataConfig.eventId)
2937
+ ? {
2938
+ ...clonedField.dataConfig,
2939
+ eventId: bindingIdMap.get(clonedField.dataConfig.eventId)
2940
+ }
2941
+ : clonedField.dataConfig;
2942
+ return {
2943
+ ...clonedField,
2944
+ ...overrides,
2945
+ events,
2946
+ dataConfig
2947
+ };
2948
+ }
2949
+ createEventDatasourceId() {
2950
+ return `evt_ds_${v4().replace(/-/g, '')}`;
2951
+ }
2917
2952
  clampIndex(index, length) {
2918
2953
  if (index < 0)
2919
2954
  return 0;
@@ -4471,6 +4506,9 @@ class FormEventRunner {
4471
4506
  if (!field || !field.events)
4472
4507
  return;
4473
4508
  const bindings = field.events.filter(b => b.on === evt.type && b.enabled !== false);
4509
+ if (evt.type === 'change' && this.isEmptyEventValue(evt.value)) {
4510
+ await this.clearInactiveApiBindingDatasources(field, bindings, evt);
4511
+ }
4474
4512
  for (const binding of bindings) {
4475
4513
  for (const action of binding.actions) {
4476
4514
  const stop = await this.executeAction(action, binding.id, evt, schema.fields);
@@ -4484,6 +4522,46 @@ class FormEventRunner {
4484
4522
  this.processingDepth--;
4485
4523
  }
4486
4524
  }
4525
+ async clearInactiveApiBindingDatasources(field, activeBindings, evt) {
4526
+ if (!this.dataSourceWriter || !field.events?.length) {
4527
+ return;
4528
+ }
4529
+ const activeBindingIds = new Set(activeBindings.map(binding => binding.id));
4530
+ const clearedDatasourceIds = new Set();
4531
+ for (const binding of field.events) {
4532
+ if (binding.enabled === false || activeBindingIds.has(binding.id)) {
4533
+ continue;
4534
+ }
4535
+ for (const action of binding.actions) {
4536
+ if (action.type !== 'api') {
4537
+ continue;
4538
+ }
4539
+ const datasourceId = this.resolveDatasourceId(action, evt);
4540
+ if (!datasourceId || clearedDatasourceIds.has(datasourceId)) {
4541
+ continue;
4542
+ }
4543
+ clearedDatasourceIds.add(datasourceId);
4544
+ try {
4545
+ await this.dataSourceWriter({
4546
+ datasourceId,
4547
+ rows: [],
4548
+ action,
4549
+ event: evt,
4550
+ response: []
4551
+ });
4552
+ this.engine.emitDataSourceUpdate(datasourceId);
4553
+ }
4554
+ catch (error) {
4555
+ this.logger.warn('Failed to clear API action datasource after the source field was emptied.', {
4556
+ event: evt,
4557
+ action,
4558
+ datasourceId,
4559
+ error
4560
+ });
4561
+ }
4562
+ }
4563
+ }
4564
+ }
4487
4565
  async executeAction(action, eventId, evt, fields) {
4488
4566
  if (action.type === 'log') {
4489
4567
  this.logger.log(action.message || 'Event fired', { event: evt });
@@ -4655,6 +4733,8 @@ class FormEventRunner {
4655
4733
  return !this.isEmptyValue(left);
4656
4734
  case 'truthy':
4657
4735
  return !!left;
4736
+ case 'notTruthy':
4737
+ return !left;
4658
4738
  default:
4659
4739
  return false;
4660
4740
  }
@@ -4737,6 +4817,18 @@ class FormEventRunner {
4737
4817
  }
4738
4818
  return [{ value }];
4739
4819
  }
4820
+ isEmptyEventValue(value) {
4821
+ if (value === undefined || value === null) {
4822
+ return true;
4823
+ }
4824
+ if (typeof value === 'string') {
4825
+ return value.trim().length === 0;
4826
+ }
4827
+ if (Array.isArray(value)) {
4828
+ return value.length === 0;
4829
+ }
4830
+ return false;
4831
+ }
4740
4832
  }
4741
4833
 
4742
4834
  const FILE_UPLOAD_CLIENT = new InjectionToken('FILE_UPLOAD_CLIENT');
@@ -5187,6 +5279,7 @@ class JsonFormRendererComponent {
5187
5279
  fieldDataAccessApi;
5188
5280
  formContentId;
5189
5281
  formContentVersion;
5282
+ refreshKey;
5190
5283
  valueChange = new EventEmitter();
5191
5284
  groupedValueChange = new EventEmitter();
5192
5285
  combinedValueChange = new EventEmitter();
@@ -5219,6 +5312,10 @@ class JsonFormRendererComponent {
5219
5312
  if (changes['mode'] && !changes['mode'].firstChange) {
5220
5313
  this.configureRunner();
5221
5314
  }
5315
+ if (changes['refreshKey'] && !changes['refreshKey'].firstChange) {
5316
+ this.createEngine();
5317
+ return;
5318
+ }
5222
5319
  if (changes['fieldDataAccessMap']
5223
5320
  || changes['fieldDataAccessApi']
5224
5321
  || changes['formContentId']
@@ -5960,7 +6057,7 @@ class JsonFormRendererComponent {
5960
6057
  || typeof record['type'] === 'string';
5961
6058
  }
5962
6059
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: JsonFormRendererComponent, deps: [{ token: DesignerStateService }], target: i0.ɵɵFactoryTarget.Component });
5963
- 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", severityEvaluationMode: "severityEvaluationMode", 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: `
6060
+ 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", severityEvaluationMode: "severityEvaluationMode", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion", refreshKey: "refreshKey" }, outputs: { valueChange: "valueChange", groupedValueChange: "groupedValueChange", combinedValueChange: "combinedValueChange", validationChange: "validationChange", uploadedFilesChange: "uploadedFilesChange", formSubmit: "formSubmit" }, usesOnChanges: true, ngImport: i0, template: `
5964
6061
  <div class="form-renderer-container"
5965
6062
  data-fd="renderer"
5966
6063
  [class.is-mobile]="device === 'mobile'"
@@ -6043,6 +6140,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
6043
6140
  type: Input
6044
6141
  }], formContentVersion: [{
6045
6142
  type: Input
6143
+ }], refreshKey: [{
6144
+ type: Input
6046
6145
  }], valueChange: [{
6047
6146
  type: Output
6048
6147
  }], groupedValueChange: [{
@@ -6244,6 +6343,7 @@ class FormJourneyViewerComponent {
6244
6343
  fieldDataAccessApi;
6245
6344
  formContentId;
6246
6345
  formContentVersion;
6346
+ refreshKey;
6247
6347
  formDataChange = new EventEmitter();
6248
6348
  formDataByPageChange = new EventEmitter();
6249
6349
  formValidationChange = new EventEmitter();
@@ -6261,9 +6361,7 @@ class FormJourneyViewerComponent {
6261
6361
  return index >= 0 ? index : 0;
6262
6362
  });
6263
6363
  ngOnInit() {
6264
- this.activePageId.set(this.journey.startPageId || this.journey.pages[0]?.id || '');
6265
- this.values.set(this.normalizeInitialValues(this.initialValues));
6266
- this.fieldLabels.set(this.normalizeInitialFieldLabels(this.initialFieldLabels));
6364
+ this.resetViewerState();
6267
6365
  }
6268
6366
  ngOnChanges(changes) {
6269
6367
  if (changes['initialValues']) {
@@ -6272,6 +6370,10 @@ class FormJourneyViewerComponent {
6272
6370
  if (changes['initialFieldLabels']) {
6273
6371
  this.fieldLabels.set(this.normalizeInitialFieldLabels(this.initialFieldLabels));
6274
6372
  }
6373
+ if (changes['refreshKey'] && !changes['refreshKey'].firstChange) {
6374
+ this.resetViewerState();
6375
+ return;
6376
+ }
6275
6377
  const current = this.activePageId();
6276
6378
  if (current && this.journey.pages.some(page => page.id === current))
6277
6379
  return;
@@ -6320,6 +6422,11 @@ class FormJourneyViewerComponent {
6320
6422
  return {};
6321
6423
  return structuredClone(value);
6322
6424
  }
6425
+ resetViewerState() {
6426
+ this.activePageId.set(this.journey.startPageId || this.journey.pages[0]?.id || '');
6427
+ this.values.set(this.normalizeInitialValues(this.initialValues));
6428
+ this.fieldLabels.set(this.normalizeInitialFieldLabels(this.initialFieldLabels));
6429
+ }
6323
6430
  toValueScope(values) {
6324
6431
  const scope = {};
6325
6432
  for (const fieldValue of Object.values(values)) {
@@ -6378,7 +6485,7 @@ class FormJourneyViewerComponent {
6378
6485
  return flattened;
6379
6486
  }
6380
6487
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormJourneyViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6381
- 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", severityEvaluationMode: "severityEvaluationMode", 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: `
6488
+ 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", severityEvaluationMode: "severityEvaluationMode", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", initialValues: "initialValues", initialFieldLabels: "initialFieldLabels", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion", refreshKey: "refreshKey" }, 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: `
6382
6489
  <div class="form-journey-viewer flex h-full w-full flex-col" data-fd="form-journey-viewer">
6383
6490
  <div class="border-b border-gray-200 bg-white px-4 py-2 text-xs text-gray-600" data-fd="journey-progress">
6384
6491
  {{ activePageIndex() + 1 }} / {{ journey.pages.length }}
@@ -6399,6 +6506,7 @@ class FormJourneyViewerComponent {
6399
6506
  [fieldDataAccessApi]="fieldDataAccessApi"
6400
6507
  [formContentId]="formContentId"
6401
6508
  [formContentVersion]="formContentVersion"
6509
+ [refreshKey]="refreshKey"
6402
6510
  [navigateToPage]="navigateToPage"
6403
6511
  (valueChange)="onValueChange($event)"
6404
6512
  (validationChange)="onValidationChange($event)"
@@ -6407,7 +6515,7 @@ class FormJourneyViewerComponent {
6407
6515
  </app-json-form-renderer>
6408
6516
  </div>
6409
6517
  </div>
6410
- `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
6518
+ `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "refreshKey"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
6411
6519
  }
6412
6520
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormJourneyViewerComponent, decorators: [{
6413
6521
  type: Component,
@@ -6436,6 +6544,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
6436
6544
  [fieldDataAccessApi]="fieldDataAccessApi"
6437
6545
  [formContentId]="formContentId"
6438
6546
  [formContentVersion]="formContentVersion"
6547
+ [refreshKey]="refreshKey"
6439
6548
  [navigateToPage]="navigateToPage"
6440
6549
  (valueChange)="onValueChange($event)"
6441
6550
  (validationChange)="onValidationChange($event)"
@@ -6469,6 +6578,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
6469
6578
  type: Input
6470
6579
  }], formContentVersion: [{
6471
6580
  type: Input
6581
+ }], refreshKey: [{
6582
+ type: Input
6472
6583
  }], formDataChange: [{
6473
6584
  type: Output
6474
6585
  }], formDataByPageChange: [{
@@ -6516,6 +6627,7 @@ class FormViewerComponent {
6516
6627
  fieldDataAccessApi;
6517
6628
  formContentId;
6518
6629
  formContentVersion;
6630
+ refreshKey;
6519
6631
  formDataChange = new EventEmitter();
6520
6632
  formDataByPageChange = new EventEmitter();
6521
6633
  formValidationChange = new EventEmitter();
@@ -6791,7 +6903,7 @@ class FormViewerComponent {
6791
6903
  return !!value && typeof value === 'object';
6792
6904
  }
6793
6905
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6794
- 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", severityEvaluationMode: "severityEvaluationMode", 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: `
6906
+ 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", severityEvaluationMode: "severityEvaluationMode", eventApis: "eventApis", eventApiExecutor: "eventApiExecutor", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion", refreshKey: "refreshKey" }, 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: `
6795
6907
  <div class="form-viewer-container flex flex-col h-full"
6796
6908
  data-fd="form-viewer"
6797
6909
  [attr.data-fd-mode]="viewOnly ? 'preview' : 'live'">
@@ -6810,6 +6922,7 @@ class FormViewerComponent {
6810
6922
  [fieldDataAccessApi]="fieldDataAccessApi"
6811
6923
  [formContentId]="formContentId"
6812
6924
  [formContentVersion]="formContentVersion"
6925
+ [refreshKey]="refreshKey"
6813
6926
  (formDataChange)="onValueChange($event)"
6814
6927
  (formDataByPageChange)="onJourneyValueByPageChange($event)"
6815
6928
  (formValidationChange)="onValidationChange($event)"
@@ -6834,6 +6947,7 @@ class FormViewerComponent {
6834
6947
  [fieldDataAccessApi]="fieldDataAccessApi"
6835
6948
  [formContentId]="formContentId"
6836
6949
  [formContentVersion]="formContentVersion"
6950
+ [refreshKey]="refreshKey"
6837
6951
  (valueChange)="onValueChange($event)"
6838
6952
  (validationChange)="onValidationChange($event)"
6839
6953
  (uploadedFilesChange)="onUploadedFilesChange($event)"
@@ -6854,7 +6968,7 @@ class FormViewerComponent {
6854
6968
  </button>
6855
6969
  </div>
6856
6970
  </div>
6857
- `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "component", type: FormJourneyViewerComponent, selector: "app-form-journey-viewer", inputs: ["journey", "viewOnly", "severityEvaluationMode", "eventApis", "eventApiExecutor", "initialValues", "initialFieldLabels", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["formDataChange", "formDataByPageChange", "formValidationChange", "uploadedFilesChange", "submit", "activePageIdChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6971
+ `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "refreshKey"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "component", type: FormJourneyViewerComponent, selector: "app-form-journey-viewer", inputs: ["journey", "viewOnly", "severityEvaluationMode", "eventApis", "eventApiExecutor", "initialValues", "initialFieldLabels", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "refreshKey"], outputs: ["formDataChange", "formDataByPageChange", "formValidationChange", "uploadedFilesChange", "submit", "activePageIdChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6858
6972
  }
6859
6973
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormViewerComponent, decorators: [{
6860
6974
  type: Component,
@@ -6877,6 +6991,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
6877
6991
  [fieldDataAccessApi]="fieldDataAccessApi"
6878
6992
  [formContentId]="formContentId"
6879
6993
  [formContentVersion]="formContentVersion"
6994
+ [refreshKey]="refreshKey"
6880
6995
  (formDataChange)="onValueChange($event)"
6881
6996
  (formDataByPageChange)="onJourneyValueByPageChange($event)"
6882
6997
  (formValidationChange)="onValidationChange($event)"
@@ -6901,6 +7016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
6901
7016
  [fieldDataAccessApi]="fieldDataAccessApi"
6902
7017
  [formContentId]="formContentId"
6903
7018
  [formContentVersion]="formContentVersion"
7019
+ [refreshKey]="refreshKey"
6904
7020
  (valueChange)="onValueChange($event)"
6905
7021
  (validationChange)="onValidationChange($event)"
6906
7022
  (uploadedFilesChange)="onUploadedFilesChange($event)"
@@ -6948,6 +7064,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
6948
7064
  type: Input
6949
7065
  }], formContentVersion: [{
6950
7066
  type: Input
7067
+ }], refreshKey: [{
7068
+ type: Input
6951
7069
  }], formDataChange: [{
6952
7070
  type: Output
6953
7071
  }], formDataByPageChange: [{
@@ -9029,7 +9147,7 @@ class LayoutCanvasComponent {
9029
9147
 
9030
9148
  <!-- Hidden file input for import -->
9031
9149
  <input type="file" #fileInput accept=".json" (change)="onFileSelected($event)" style="display: none;">
9032
- `, 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", "severityEvaluationMode", "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"] }] });
9150
+ `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "refreshKey"], 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"] }] });
9033
9151
  }
9034
9152
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutCanvasComponent, decorators: [{
9035
9153
  type: Component,
@@ -17177,7 +17295,8 @@ class QueryBuilderComponent {
17177
17295
  { label: 'Contains', value: 'contains' },
17178
17296
  { label: 'Is Empty', value: 'empty' },
17179
17297
  { label: 'Not Empty', value: 'notEmpty' },
17180
- { label: 'Is Truthy', value: 'truthy' }
17298
+ { label: 'Is Truthy', value: 'truthy' },
17299
+ { label: 'Is Not Truthy', value: 'notTruthy' }
17181
17300
  ];
17182
17301
  fieldOptions() {
17183
17302
  return [
@@ -17259,7 +17378,7 @@ class QueryBuilderComponent {
17259
17378
  this.emitChange();
17260
17379
  }
17261
17380
  requiresValue(operator) {
17262
- return !['empty', 'notEmpty', 'truthy'].includes(operator);
17381
+ return !['empty', 'notEmpty', 'truthy', 'notTruthy'].includes(operator);
17263
17382
  }
17264
17383
  conditionValueSource(condition) {
17265
17384
  return condition.valueSource === 'field' ? 'field' : 'literal';
@@ -19638,7 +19757,7 @@ class FormPreviewComponent {
19638
19757
  </div>
19639
19758
  </div>
19640
19759
  </div>
19641
- `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
19760
+ `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "refreshKey"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
19642
19761
  }
19643
19762
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormPreviewComponent, decorators: [{
19644
19763
  type: Component,
@@ -23646,7 +23765,8 @@ class EventsWorkspaceComponent {
23646
23765
  { label: 'Ends With', value: 'endsWith' },
23647
23766
  { label: 'Is Empty', value: 'empty' },
23648
23767
  { label: 'Is Not Empty', value: 'notEmpty' },
23649
- { label: 'Is Truthy', value: 'truthy' }
23768
+ { label: 'Is Truthy', value: 'truthy' },
23769
+ { label: 'Is Not Truthy', value: 'notTruthy' }
23650
23770
  ];
23651
23771
  currentSchema = computed(() => this.draftSchema() ?? this.schema());
23652
23772
  fields = computed(() => this.flattenFields(this.currentSchema()));
@@ -24124,7 +24244,7 @@ class EventsWorkspaceComponent {
24124
24244
  this.updateNavigateConditionGroup(bindingIndex, actionIndex, this.toNavigateLogicGroup(next));
24125
24245
  }
24126
24246
  navigateOperatorNeedsValue(operator) {
24127
- return !['empty', 'notEmpty', 'truthy'].includes(operator);
24247
+ return !['empty', 'notEmpty', 'truthy', 'notTruthy'].includes(operator);
24128
24248
  }
24129
24249
  navigateConditionFields() {
24130
24250
  return this.fields().map(field => ({
@@ -26293,7 +26413,7 @@ class FormDesignerShellComponent {
26293
26413
  </div>
26294
26414
  </section>
26295
26415
  </div>
26296
- `, 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", "severityEvaluationMode", "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"] }] });
26416
+ `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "refreshKey"], 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"] }] });
26297
26417
  }
26298
26418
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormDesignerShellComponent, decorators: [{
26299
26419
  type: Component,
@@ -31547,7 +31667,7 @@ class WebsitePreviewShellComponent {
31547
31667
  }
31548
31668
  </main>
31549
31669
  </div>
31550
- `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
31670
+ `, 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", "severityEvaluationMode", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion", "refreshKey"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
31551
31671
  }
31552
31672
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: WebsitePreviewShellComponent, decorators: [{
31553
31673
  type: Component,
@@ -32681,6 +32801,10 @@ class TextFieldWidgetComponent {
32681
32801
  this.clearResolvedValue();
32682
32802
  return;
32683
32803
  }
32804
+ if (clearWhenMissing && !(await this.hasResolvedRows())) {
32805
+ this.clearResolvedValue();
32806
+ return;
32807
+ }
32684
32808
  const val = await this.dataProvider.getValue(this.config, this.engine);
32685
32809
  this.displayPrefix = await this.dataProvider.getValueDisplayPrefix(this.config, this.engine);
32686
32810
  if (val === undefined || val === null) {
@@ -32700,6 +32824,10 @@ class TextFieldWidgetComponent {
32700
32824
  // Ignore failed datasource refreshes; field remains editable.
32701
32825
  }
32702
32826
  }
32827
+ async hasResolvedRows() {
32828
+ const rows = await this.dataProvider.getList(this.config, this.engine);
32829
+ return rows.length > 0;
32830
+ }
32703
32831
  clearResolvedValue() {
32704
32832
  this.displayPrefix = '';
32705
32833
  this.control.setValue(null, { emitEvent: false });